home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / sketch / source / appleevent / oslclassgraphicobject.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-25  |  87.6 KB  |  3,337 lines

  1. /****************************************************************************
  2.  * 
  3.  * OSLClassGraphicObject.c
  4.  * 
  5.  * OSL support for the cGraphicObject Apple Event Registry object
  6.  *
  7.  ****************************************************************************/
  8.  
  9. #include <stdio.h>            // for sprintf()
  10. #include <string.h>            // for strlen()
  11. #include <Errors.h>
  12.  
  13. #include "OSLClassGraphicObject.h"
  14. #include "OSLClassDocument.h"
  15. #include "AERCoreSuite.h"
  16. #include "AppleEvent.h"
  17.  
  18. #include "Documents.h"
  19. #include "DocumentADT.h"
  20. #include "DocumentHelpers.h"
  21.  
  22.  
  23. #include "ElementADT.h"
  24. #include "ElementHelpers.h"
  25.  
  26. #include "Assertion.h"
  27.  
  28. #include "StringUtils.h"
  29.  
  30. #include "OSLHelpers.h"
  31.  
  32. #include "Imaging.h"
  33.  
  34. // ----------------------------------------------------------------------------
  35. //                      Core Suite Object Event handlers
  36. // ----------------------------------------------------------------------------
  37.  
  38. static OSErr HandleCount            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  39. static OSErr HandleDataSize        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  40. static OSErr HandleDelete            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  41. static OSErr HandleDuplicate        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  42. static OSErr HandleExists            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  43. static OSErr HandleGetData            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  44. static OSErr HandleMake                (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  45. static OSErr HandleMove                (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  46. static OSErr HandleSetData            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  47.  
  48. // ----------------------------------------------------------------------------
  49. //                              Object Accessor functions
  50. // ----------------------------------------------------------------------------
  51.  
  52. static OSErr 
  53. MakeNewObject(    
  54.         const DescType         objectToCreate,
  55.           const DescType         insertionPosition,
  56.         const AEDesc         *token,
  57.         const AEDesc         *ptrToWithData, 
  58.         const AEDesc         *ptrToWithProperties,
  59.         AppleEvent             *reply);
  60.  
  61.  
  62. static OSErr 
  63. PropertyFromListAccessor(
  64.                  DescType        desiredClass,
  65.         const AEDesc*        containerToken,
  66.                 DescType        containerClass,
  67.                 DescType        keyForm,
  68.         const AEDesc*        keyData,
  69.                 AEDesc*        resultToken,
  70.                 long             refcon);
  71.  
  72. static OSErr 
  73. PropertyFromObjectAccessor(
  74.                  DescType        desiredClass,
  75.         const AEDesc*        containerToken,
  76.                 DescType        containerClass,
  77.                 DescType        keyForm,
  78.         const AEDesc*        keyData,
  79.                 AEDesc*        resultToken,
  80.                 long             refcon);
  81.  
  82. static OSErr    GetDataFromList        (AEDesc *srcList, AEDesc *desiredTypes, AEDesc *dstList);
  83. static OSErr    GetDataFromObject        (AEDesc *token,   AEDesc *desiredTypes, AEDesc *data);
  84.  
  85. static OSErr    SetDataForList            (AEDesc *token, AEDesc *data);
  86. static OSErr    SetDataForObject        (AEDesc *token, AEDesc *data);
  87.  
  88. static Boolean CanGetProperty        (DescType class, DescType property);
  89. static Boolean CanSetProperty        (DescType class, DescType property);
  90. static OSErr     SetProperties        (DocumentReference document, ElementReference element, AEDesc *propertyRecord);
  91.  
  92. // ----------------------------------------------------------------------------
  93. // -----  cGraphicObject - accessors for everything graphical
  94. // ----------------------------------------------------------------------------
  95.  
  96. static pascal OSErr 
  97. GraphicObjectFromDocumentAccessor(DescType    desiredClass,
  98.                                      const AEDesc*        containerToken,
  99.                                              DescType        containerClass,   // cDocument
  100.                                              DescType        keyForm,
  101.                                     const AEDesc*        keyData,
  102.                                              AEDesc*        resultToken,
  103.                                              long             refcon);
  104.  
  105. static pascal OSErr 
  106. GraphicObjectFromGroupAccessor  (DescType        desiredClass,
  107.                                      const AEDesc*        containerToken,
  108.                                              DescType        containerClass,   // cGroupedGraphic
  109.                                              DescType        keyForm,
  110.                                     const AEDesc*        keyData,
  111.                                              AEDesc*        resultToken,
  112.                                              long             refcon);
  113.  
  114.  
  115. static pascal OSErr 
  116. GraphicObjectAccessor(               ElementList list,
  117.                                             DescType        desiredClass,        // any subclass of cGraphicObject
  118.                                      const AEDesc*        containerToken,
  119.                                              DescType        containerClass,
  120.                                              DescType        keyForm,
  121.                                     const AEDesc*        keyData,
  122.                                              AEDesc*        resultToken,        // specified object is returned in result
  123.                                              long             refcon   );
  124.  
  125. // ----------------------------------------------------------------------------
  126. // Application-specific helpers
  127. // ----------------------------------------------------------------------------
  128.  
  129. static OSErr             DoMove                                (AEDesc *token, DescType insertionPos, AEDesc *toToken);
  130.  
  131. static OSErr             MakePolygonFromAEPointList        (DocumentReference document, ElementReference element, AEDescList* list);
  132. static OSErr           MakeGroupFromAEList                (DocumentReference document, ElementReference element, AEDescList* list);
  133.  
  134. static OSErr             ProcessFormRelativePostition    (const AEDesc* containerToken, const AEDesc *keyData, DescType desiredClass, ElementReference *element);
  135.  
  136. static PolyHandle     CreatePolygonFromPoints            (short numberOfPoints, Point *pointList);
  137. static short             CountPolygonPoints                (PolyHandle polygon);
  138. static Point             GetPolygonPoint                    (PolyHandle polygon, short pointIndex);
  139.  
  140. /*****************************************************************************
  141.  * 
  142.  * GraphicObjectEventDispatcher
  143.  *
  144.  *    Handles AppleEvents for graphic objects
  145.  * 
  146.  *****************************************************************************/
  147.  
  148. OSErr
  149. GraphicObjectEventDispatcher(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  150. {
  151.     OSErr error = noErr;
  152.     
  153.     AEEventID    eventID;
  154.     OSType        typeCode;
  155.     Size            actualSize = 0L;
  156.     
  157.     // Get the event ID
  158.     
  159.     error = AEGetAttributePtr(appleEvent, 
  160.                                       keyEventIDAttr, 
  161.                                       typeType, 
  162.                                       &typeCode, 
  163.                                       (Ptr)&eventID, 
  164.                                       sizeof(eventID), 
  165.                                       &actualSize);
  166.     if (error != noErr) {
  167.         return error;
  168.     }
  169.     
  170.     switch (eventID) 
  171.     {
  172.         case kAEClone:
  173.             error = HandleDuplicate(token, appleEvent, reply, refcon);
  174.             break;
  175.             
  176.         case kAECountElements:
  177.             error = HandleCount(token, appleEvent, reply, refcon);
  178.             break;
  179.             
  180.         case kAECreateElement:
  181.             error = HandleMake(token, appleEvent, reply, refcon);
  182.             break;
  183.             
  184.         case kAEDelete:
  185.             error = HandleDelete(token, appleEvent, reply, refcon);
  186.             break;
  187.             
  188.         case kAEDoObjectsExist:
  189.             error = HandleExists(token, appleEvent, reply, refcon);
  190.             break;
  191.             
  192.         case kAEGetData:
  193.             error = HandleGetData(token, appleEvent, reply, refcon);
  194.             break;
  195.             
  196.         case kAEGetDataSize:
  197.             error = HandleDataSize(token, appleEvent, reply, refcon);
  198.             break;
  199.             
  200.         case kAEMove:
  201.             error = HandleMove(token, appleEvent, reply, refcon);
  202.             break;
  203.             
  204.         case kAESetData:
  205.             error = HandleSetData(token, appleEvent, reply, refcon);
  206.             break;
  207.  
  208.         default:
  209.             error = errAEEventNotHandled;
  210.             break;
  211.     }
  212.  
  213.     if (error != noErr && reply != NULL && reply->descriptorType != typeNull)
  214.         PutReplyErrorNumber(reply, error);
  215.     
  216.     return error;
  217. }
  218.  
  219. #pragma mark -
  220. // ----------------------------------------------------------------------------
  221. //                      Core Suite Object Event handlers
  222. // ----------------------------------------------------------------------------
  223. // This function counts anything that can be contained inside of a Graphic Object
  224. // It currently just counts things inside a grouped graphic object.
  225.  
  226. static OSErr 
  227. HandleCount(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  228. {
  229.     #pragma unused (refcon)
  230.  
  231.     OSErr                    error                 = noErr;    
  232.     long                    numberOfObjects    = 0L;
  233.     DescType                objectClass         = 0L;
  234.  
  235.     DocumentReference document                = nil;
  236.     ElementReference  element                = nil;
  237.     ElementType       elementType;
  238.     
  239.     // Get the class of object that we will count
  240.  
  241.     error = GetObjectClassFromAppleEvent(appleEvent, &objectClass);
  242.     if (error) 
  243.         goto CleanUp;
  244.  
  245.     // Make sure we got & handled all of the required parameters
  246.     
  247.     error = CheckForUnusedParameters(appleEvent);
  248.     if (error) 
  249.         goto CleanUp;
  250.  
  251.     // a token list could be sent to this handler by a formWhose resolution,
  252.     // such as "count rectangles whose width > 100"
  253.     
  254.     if (token->descriptorType == typeAEList)
  255.     {
  256.         AEDescList flatList = {typeNull, nil};
  257.         
  258.         error = AECreateList(NULL, 0L, false, &flatList);
  259.         if (error == noErr)
  260.             error = FlattenAEList(token, &flatList);
  261.             
  262.         if (error == noErr)
  263.             error = AECountItems(token, &numberOfObjects);
  264.             
  265.         if (error == noErr)
  266.             error = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&numberOfObjects, sizeof(long));
  267.             
  268.         AEDisposeDesc(&flatList);
  269.         
  270.         goto CleanUp;
  271.     }
  272.     
  273.     error = GetDocumentReferenceFromToken(token, &document);
  274.     if (error != noErr)
  275.         goto CleanUp;
  276.         
  277.     error = GetElementReferenceFromToken(token, &element);
  278.     if (error != noErr)
  279.         goto CleanUp;
  280.         
  281.     elementType = GetElementType(element);
  282.     
  283.     if (elementType == kGroup)
  284.     {
  285.         if (error == noErr)
  286.             numberOfObjects = CountElementsByClass(GetSubElementList(element), objectClass);
  287.     }
  288.     else
  289.     {
  290.         error = errAECantHandleClass;
  291.     }    
  292.  
  293.     // Now return the result in the reply apple event
  294.             
  295.     if (error == noErr && reply->descriptorType != typeNull)
  296.         error = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&numberOfObjects, sizeof(long));
  297.  
  298. CleanUp:
  299.     
  300.     return error;
  301. }
  302.  
  303. // ----------------------------------------------------------------------------
  304. // Just get the data in a handle and return its handle size
  305.  
  306. static OSErr 
  307. HandleDataSize(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  308. {
  309.     OSErr     error = noErr;
  310.     AEDesc    data     = {typeNull, nil};    
  311.     long        size  = 0L;
  312.     
  313.     // First, get the data
  314.     error = HandleGetData(token, appleEvent, reply, refcon);
  315.     
  316.     // now, extract it from the reply
  317.     
  318.     if (error == noErr)
  319.         error = AEGetKeyDesc(reply, 
  320.                                     keyDirectObject, 
  321.                                     typeWildCard, 
  322.                                     &data);
  323.         
  324.     if (error == noErr)
  325.     {
  326.         if (data.dataHandle != nil)
  327.         {
  328.             size = GetHandleSize(data.dataHandle);
  329.         }                         
  330.         error = AEPutParamPtr(reply, 
  331.                                      keyAEResult, 
  332.                                      typeLongInteger, 
  333.                                      (Ptr)&size, 
  334.                                      sizeof(long));
  335.     }
  336.  
  337.     AEDisposeDesc(&data);
  338.     
  339.     return error;
  340.  
  341. }
  342.  
  343. // ----------------------------------------------------------------------------
  344. // Delete a Graphic Object
  345.  
  346. static OSErr HandleDelete(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  347. {
  348.     #pragma unused (reply, refcon)
  349.  
  350.     OSErr                 error             = noErr;
  351.     
  352.     DocumentReference    document         = nil;
  353.     ElementReference    element            = nil;
  354.     
  355.     // Make sure we got & handled all of the required parameters
  356.     
  357.     error = CheckForUnusedParameters(appleEvent);
  358.     if (error) 
  359.         goto CleanUp;
  360.     
  361.     if (token->descriptorType == typeAEList)
  362.     {
  363.         long             index;
  364.         long             numItems;
  365.         AEKeyword     keyword;
  366.         AEDesc        item;
  367.         
  368.         AEDescList flatList = {typeNull, nil};
  369.         
  370.         error = AECreateList(NULL, 0L, false, &flatList);
  371.         if (error == noErr)
  372.             error = FlattenAEList(token, &flatList);
  373.             
  374.         if (error == noErr)
  375.         {
  376.             error = AECountItems(token, &numItems);
  377.             
  378.             for (index = numItems; index >= 1; index--)
  379.             {
  380.                error = AEGetNthDesc(&flatList, index, typeWildCard, &keyword, &item);
  381.                
  382.                if (error == noErr)
  383.                     error = GetDocumentReferenceFromToken(&item, &document);
  384.                 
  385.                 if (error == noErr)
  386.                     error = GetElementReferenceFromToken(&item, &element);
  387.                 
  388.                 if (error == noErr)
  389.                 {
  390.                     IMDelete(document, element);
  391.                     MarkDocumentAsChanged(document);
  392.                 }
  393.                 
  394.                 AEDisposeDesc(&item);
  395.             }
  396.         }
  397.         AEDisposeDesc(&flatList);
  398.     }
  399.     else
  400.     {
  401.         error = GetDocumentReferenceFromToken(token, &document);
  402.         
  403.         if (error == noErr)
  404.             error = GetElementReferenceFromToken(token, &element);
  405.         
  406.         if (error == noErr)
  407.         {
  408.             IMDelete(document, element);
  409.             MarkDocumentAsChanged(document);        // and the document has now been modified!
  410.         }
  411.     }
  412. CleanUp:
  413.  
  414.     return error;
  415. }
  416.  
  417. // ----------------------------------------------------------------------------
  418. // receives messages like "duplicate rectangle 1 of document 1" messages
  419.  
  420. static OSErr 
  421. HandleDuplicate(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  422. {
  423.     #pragma unused (refcon)
  424.  
  425.     OSErr error                              = noErr;
  426.     
  427.     DocumentReference document          = nil;
  428.     
  429.     ElementReference  oldElement         = nil;
  430.     ElementReference  newElement         = nil;
  431.     ElementReference  insElement     = nil;
  432.     
  433.     OSType                typeCode;
  434.     Size                    actualSize;
  435.  
  436.     DescType                insertionPos    = typeNull;
  437.     AEDesc                insertionLoc    = {typeNull, nil};
  438.     AEDesc                objectSpec        = {typeNull, nil};
  439.     AEDesc            insertionToken = {typeNull, nil};
  440.     
  441.     error = GetDocumentReferenceFromToken(token, &document);
  442.     
  443.     if (error == noErr)
  444.         error = GetElementReferenceFromToken(token, &oldElement);
  445.  
  446.     //    For Duplicate, there is an OPTIONAL typeInsertionLoc record
  447.     // which will be there when the script contains something like
  448.     // "duplicate oval 1 to after rectangle 3". If this parameter is found,
  449.     // we coerce the insertionLoc record into an AERecord so we can extract the fields.     
  450.     // Notice that this is a OPTIONAL parameter, so we give it a default behavior
  451.     // by duplicating to after the source element.
  452.     
  453.     error = AEGetParamDesc(appleEvent,                 // Extract as a AERecord
  454.                                   keyAEInsertHere, 
  455.                                   typeAERecord, 
  456.                                   &insertionLoc);
  457.  
  458.     if (error == errAEDescNotFound)
  459.     {
  460.         insertionPos = kAEBeginning;
  461.         error        = noErr;
  462.     }
  463.     else if (error == noErr)
  464.     {
  465.  
  466.         // Get the enumerated insertion location (at end, in front, before, after, replace.)
  467.         
  468.         error = AEGetKeyPtr(&insertionLoc, 
  469.                                       keyAEPosition,             // insertion location
  470.                                     typeEnumeration, 
  471.                                     &typeCode, 
  472.                                     (Ptr)&insertionPos,
  473.                                    sizeof(insertionPos), 
  474.                                    &actualSize);
  475.                                    
  476.         //    Extract and resolve the object specifier from the insertion location record.
  477.         // In a case like "make new rectangle before rectangle 1 of document 1",
  478.         // the ospec will resolve to "rectangle 1 of document 1"
  479.                  
  480.         error = AEGetKeyDesc(&insertionLoc, 
  481.                                     keyAEObject, 
  482.                                     typeWildCard, 
  483.                                     &objectSpec);
  484.     }
  485.                         
  486.     // if there was a object specifier in the insertion location (eg, "before rectangle 1 of document 1",
  487.     //   then we call AEResolve() to get a token for it,
  488.     // Otherwise, is was something like "at end" or "at beginning", which is also OK, 
  489.     //   then deal with it correctly later.
  490.  
  491.     if (objectSpec.descriptorType != typeNull) 
  492.     {
  493.         error = AEResolve(&objectSpec, 
  494.                              kAEIDoMinimum, 
  495.                              &insertionToken);
  496.                              
  497.         if (error == noErr) 
  498.         {
  499.             error = GetElementReferenceFromToken(&insertionToken, &insElement);
  500.         }
  501.         else
  502.         {
  503.             goto CleanUp;
  504.         }
  505.     }
  506.     
  507.     // ----------- create the new element ------------------
  508.     
  509.     if (error == noErr)
  510.     {
  511.         newElement = CloneElement(oldElement);
  512.         error = ElementError();
  513.         
  514.         if (newElement != nil && error == noErr)
  515.         {
  516.             if (insElement == nil)
  517.             {
  518.                 AdoptOrphanInsertingBeforeElement(newElement, oldElement);    // visually, behind the source element
  519.             }
  520.             else
  521.             {
  522.                 switch (insertionPos)
  523.                 {
  524.                     case kAEBeginning:
  525.                         // add new element to end of the list
  526.                         AdoptOrphan(GetDocumentElementList(document), newElement);
  527.                         break;
  528.                         
  529.                     case kAEEnd:
  530.                         // add new element to the beginning of the list
  531.                         insElement = GetFirstElement(GetDocumentElementList(document));
  532.                         if (insElement != nil)
  533.                         {
  534.                             AdoptOrphanInsertingBeforeElement(newElement, insElement);
  535.                         }
  536.                         break;
  537.                         
  538.                     case kAEBefore:
  539.                         AdoptOrphanInsertingAfterElement(newElement, insElement);
  540.                         break;
  541.                         
  542.                     case kAEAfter:
  543.                         AdoptOrphanInsertingBeforeElement(newElement, insElement);
  544.                         break;
  545.                         
  546.                     case kAEReplace:
  547.                         AdoptOrphanInsertingAfterElement(newElement, insElement);
  548.                         DestroyElement(insElement);
  549.                         break;
  550.                         
  551.                     default:
  552.                         SysBeep(2);
  553.                         break;    
  554.                 }            
  555.             }
  556.             
  557.             IMDraw(document);
  558.             MarkDocumentAsChanged(document);
  559.         }
  560.     }
  561.  
  562.     // return a reference to the new graphic object in the AppleEvent reply parameter
  563.     
  564.     if (error == noErr && reply != NULL && document != nil && newElement != nil)
  565.     {
  566.         AEDesc ospec = {typeNull, nil};
  567.  
  568.         error = CreateGraphicObjectOSpec(document, newElement, &ospec);
  569.         
  570.         if (error == noErr)
  571.         {
  572.             AEPutParamDesc(reply, keyDirectObject, &ospec);
  573.         }
  574.     
  575.         AEDisposeDesc(&ospec);
  576.     }
  577.  
  578. CleanUp:
  579.  
  580.     AEDisposeDesc(&insertionLoc);
  581.     AEDisposeDesc(&insertionToken);
  582.     AEDisposeDesc(&objectSpec);
  583.  
  584.     return error;
  585. }
  586.  
  587. // ----------------------------------------------------------------------------
  588. // "If <rectangle 1 of document 1> exists..."
  589. // The AEResolve() function in AERCoreSuite.c will already have filtered
  590. // out all cases where the object did not exist, so this function should
  591. // always return TRUE.
  592.  
  593. static OSErr 
  594. HandleExists(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  595. {
  596.     #pragma unused (token, appleEvent, refcon)
  597.  
  598.     OSErr error         = noErr;
  599.     Boolean foundIt    = true;
  600.  
  601.     error = AEPutParamPtr(reply, 
  602.                      keyAEResult, 
  603.                      typeBoolean, 
  604.                      (Ptr)&foundIt, 
  605.                      sizeof(Boolean));
  606.         
  607.     return error;
  608. }
  609.  
  610. // ----------------------------------------------------------------------------
  611.  
  612. static OSErr 
  613. HandleGetData(AEDesc *tokenOrTokenList, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  614. {
  615.     #pragma unused (refcon)
  616.  
  617.     OSErr             error             = noErr;    
  618.     AEDesc            data                 = {typeNull, nil};
  619.     AEDesc            desiredTypes   = {typeNull, nil};
  620.     
  621.     AEGetParamDesc(appleEvent, keyAERequestedType, typeAEList, &desiredTypes);
  622.     
  623.     error = GetDataFromGraphicObject(tokenOrTokenList, &desiredTypes, &data);
  624.  
  625.     if (error == noErr && reply->descriptorType != typeNull)
  626.         error = AEPutKeyDesc(reply, keyDirectObject, &data);    // return the requested data in the reply
  627.         
  628.     AEDisposeDesc(&data);
  629.     AEDisposeDesc(&desiredTypes);
  630.     
  631.     return error;
  632. }
  633.  
  634. // ----------------------------------------------------------------------------
  635. // On entry, the token is a simple AEDesc that just contains the type of object
  636. // we are expected to create. We also extract properties and data, which can be
  637. // used to initialize the new object. In addition, there is an insertion location
  638. // telling us where to insert the new element.
  639.  
  640. static OSErr 
  641. HandleMake(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  642. {
  643.     #pragma unused (refcon)
  644.  
  645.     OSErr                 error             = noErr;
  646.     
  647.     OSType                typeCode;
  648.     Size                    actualSize;
  649.  
  650.     DescType                newObjClass        = typeNull;
  651.     DescType                insertionPos    = typeNull;
  652.     
  653.     AEDesc                insertionLoc    = {typeNull, nil};
  654.     AEDesc                objectSpec        = {typeNull, nil};
  655.  
  656.     long                    documentNumber = 0L;
  657.     unsigned long         elementNumber  = 0L;
  658.  
  659.     DocumentReference document         = nil;
  660.     ElementReference  newElement        = nil;
  661.     ElementReference  oldElement         = nil;
  662.  
  663.     // Optional parameters
  664.     AEDesc                 withData            = {typeNull, nil};
  665.     AEDesc                 withProperties    = {typeNull, nil};
  666.  
  667.     AEDesc                 *ptrToWithData            = NULL;
  668.     AEDesc               *ptrToWithProperties    = NULL;
  669.  
  670.     newObjClass = **(DescType**)(token->dataHandle);        // This is the class of object we should create
  671.     
  672.     //    For Create Element, the object specifier is contained in  
  673.     //    a typeInsertionLoc record instead of in a direct parameter. 
  674.     // We coerce the insertionLoc record into an AERecord so we can extract the fields.     
  675.     // Notice that this is a REQUIRED parameter, but we give it a default behavior
  676.     // by creating a new element at beginning of the first document
  677.     
  678.     error = AEGetParamDesc(appleEvent,                 // Extract as a AERecord
  679.                                   keyAEInsertHere, 
  680.                                   typeAERecord, 
  681.                                   &insertionLoc);
  682.  
  683.     if (error == errAEDescNotFound)
  684.     {
  685.         insertionPos = kAEBeginning;
  686.         error        = noErr;
  687.     }
  688.     else if (error == noErr)
  689.     {
  690.  
  691.         // Get the enumerated insertion location (at end, in front, before, after, replace.)
  692.         
  693.         error = AEGetKeyPtr(&insertionLoc, 
  694.                                       keyAEPosition,             // insertion location
  695.                                     typeEnumeration, 
  696.                                     &typeCode, 
  697.                                     (Ptr)&insertionPos,
  698.                                    sizeof(insertionPos), 
  699.                                    &actualSize);
  700.                                    
  701.         //    Extract and resolve the object specifier from the insertion location record.
  702.         // In a case like "make new rectangle before rectangle 1 of document 1",
  703.         // the ospec will resolve to "rectangle 1 of document 1"
  704.                  
  705.         error = AEGetKeyDesc(&insertionLoc, 
  706.                                     keyAEObject, 
  707.                                     typeWildCard, 
  708.                                     &objectSpec);
  709.                                     
  710.     }
  711.                         
  712.     // if there was a object specifier in the insertion location (eg, "before rectangle 1 of document 1",
  713.     //   then we call AEResolve() to get a token for it,
  714.     // Otherwise, is was something like "at end" or "at beginning", which is also OK, 
  715.     //   then deal with it correctly later.
  716.  
  717.     if (objectSpec.descriptorType == typeNull) 
  718.     {
  719.         AEDisposeDesc(token);            // destroy it's old representation, token will now be null descriptor
  720.     }
  721.     else
  722.     {
  723.         error = AEResolve(&objectSpec, 
  724.                              kAEIDoMinimum, 
  725.                              token);            // token will contain info about the object to insert before, after, etc.
  726.                              
  727.         if (error != noErr)
  728.         {
  729.             goto CleanUp;
  730.         }
  731.     }
  732.     
  733.     switch (newObjClass)
  734.     {
  735.         case cOval:                            // Sketch can make these graphic objects
  736.         case cPolygon:
  737.         case cRectangle:
  738.         case cRoundedRectangle:
  739.         case cGraphicLine:
  740.         case cGroupedGraphic:
  741.             error = noErr;
  742.             break;
  743.         
  744.         default:
  745.             error = errAEEventNotHandled;
  746.             break;
  747.     }
  748.  
  749.     // Extract the optional parameters from the AppleEvent
  750.     
  751.     // ----- [with data ....] -----
  752.     
  753.     error = AEGetParamDesc(appleEvent, 
  754.                                   keyAEData,
  755.                                   typeWildCard,
  756.                                   &withData);
  757.                                   
  758.     if (error != noErr && error != errAEDescNotFound) 
  759.         goto CleanUp;
  760.     
  761.     if (error == errAEDescNotFound)
  762.         error = noErr;
  763.     else    
  764.         ptrToWithData = &withData;
  765.     
  766.     // ----- [with properties {property: value, ...}] -----
  767.     
  768.     error = AEGetParamDesc(appleEvent, 
  769.                                   keyAEPropData, 
  770.                                   typeWildCard, 
  771.                                   &withProperties);
  772.                                   
  773.     if (error != noErr && error != errAEDescNotFound) 
  774.         goto CleanUp;
  775.  
  776.     if (error == errAEDescNotFound)
  777.         error = noErr;
  778.     else    
  779.         ptrToWithProperties = &withProperties;
  780.         
  781.     // Finally, use the token and other parameters to create & initialize the object
  782.  
  783.     if (error == noErr)
  784.         error = MakeNewObject(newObjClass, insertionPos, token, ptrToWithData, ptrToWithProperties, reply);
  785.     
  786. CleanUp:    
  787.  
  788.     AEDisposeDesc(&insertionLoc);
  789.     AEDisposeDesc(&objectSpec);
  790.     AEDisposeDesc(&withData);
  791.     AEDisposeDesc(&withProperties);
  792.  
  793.     return error;
  794. }
  795.  
  796. // ----------------------------------------------------------------------------
  797. // Move a graphic object: On entry, the token parameter contains the resolution
  798. // of the object we want to move. The direct parameter is a object specifier for 
  799.  
  800. static OSErr 
  801. HandleMove(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  802. {
  803.     #pragma unused (refcon)
  804.  
  805.     OSErr         error          = noErr;
  806.  
  807.     OSType        typeCode;
  808.     Size            actualSize;
  809.  
  810.     DescType        insertionPos = kAEBeginning;
  811.     
  812.     AEDesc         objectSpec   = {typeNull, nil};
  813.     AEDesc         result       = {typeNull, nil};
  814.     AEDesc         insertionLoc = {typeNull, nil};
  815.     AEDesc      toToken      = {typeNull, nil};
  816.         
  817.     // The insertion location is an object specifier that results from an
  818.     // expression such as "to behind rectangle 3"
  819.     // Now is the time to parse it
  820.     
  821.     error = AEGetParamDesc(appleEvent,                 // Extract insertion location as a AERecord
  822.                                   keyAEInsertHere, 
  823.                                   typeAERecord, 
  824.                                   &insertionLoc);
  825.  
  826.     if (error == errAEDescNotFound)
  827.     {
  828.         insertionPos = kAEBeginning;
  829.         error        = noErr;
  830.     }
  831.     else if (error == noErr)
  832.     {
  833.  
  834.         // Get the enumerated insertion location (at end, in front, before, after, replace.)
  835.         
  836.         error = AEGetKeyPtr(&insertionLoc, 
  837.                                       keyAEPosition,             // insertion location
  838.                                     typeEnumeration, 
  839.                                     &typeCode, 
  840.                                     (Ptr)&insertionPos,
  841.                                    sizeof(insertionPos), 
  842.                                    &actualSize);
  843.                                    
  844.         //    Extract and resolve the object specifier from the insertion location record.
  845.         // In a case like "move oval 1 to before rectangle 1 of document 1",
  846.         // the ospec will resolve to "rectangle 1 of document 1"
  847.                  
  848.         error = AEGetKeyDesc(&insertionLoc, 
  849.                                     keyAEObject, 
  850.                                     typeWildCard, 
  851.                                     &objectSpec);
  852.     }
  853.                         
  854.     // if there was a object specifier in the insertion location (eg, "before rectangle 1 of document 1",
  855.     //   then we call AEResolve() to get a token for it,
  856.     // Otherwise, is was something like "at end" or "at beginning", which is also OK, 
  857.     //   then deal with it correctly later.
  858.  
  859.     if (objectSpec.descriptorType != typeNull) 
  860.     {
  861.         error = AEResolve(&objectSpec, 
  862.                              kAEIDoMinimum, 
  863.                              &toToken);            // token will contain info about the object to move before, after, etc.
  864.                              
  865.         if (error != noErr) 
  866.         {
  867.             goto CleanUp;
  868.         }
  869.     }
  870.  
  871.     // Make sure we got & handled all of the required parameters
  872.     
  873.     error = CheckForUnusedParameters(appleEvent);
  874.     if (error) 
  875.         goto CleanUp;
  876.     
  877.     // Do the application-specific part of the job
  878.     
  879.     error = DoMove(token, insertionPos, &toToken);
  880.     if (error != noErr)
  881.         goto CleanUp;
  882.         
  883.     // Return, in the AppleEvent reply, a reference to the object that was moved
  884.     
  885.     if (reply->dataHandle)
  886.     {
  887.         AEDesc                 ospec         = {typeNull, nil};
  888.         DocumentReference document    = nil;
  889.         ElementReference  element         = nil;
  890.  
  891.         GetDocumentReferenceFromToken(token, &document);
  892.         GetElementReferenceFromToken(token,  &element);
  893.     
  894.         error = CreateGraphicObjectOSpec(document, element, &ospec);
  895.         
  896.         if (error == noErr)
  897.         {
  898.             AEPutParamDesc(reply, keyDirectObject, &ospec);
  899.         }
  900.     
  901.         AEDisposeDesc(&ospec);
  902.     }
  903.         
  904. CleanUp:
  905.     AEDisposeDesc(&objectSpec);
  906.     AEDisposeDesc(&insertionLoc);
  907.     AEDisposeDesc(&toToken);
  908.  
  909.     return error;
  910. }
  911.  
  912. // ----------------------------------------------------------------------------
  913. // Set data basically passes responsibility to WriteToken() below. However,
  914. // one important task here is to filter out properties that are read-only.
  915.  
  916. static OSErr 
  917. HandleSetData(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  918. {
  919.     #pragma unused (reply, refcon)
  920.  
  921.     OSErr             error          = noErr;    
  922.     AEDesc            data           = {typeNull, nil};
  923.     
  924.     DescType             propertyCode;
  925.     DescType            objectClass;
  926.     
  927.     switch (token->descriptorType)
  928.     {
  929.         case typeAEList:
  930.             error = ExtractKeyDataParameter(appleEvent, &data);
  931.             if (error == noErr)
  932.                 error = SetDataForList(token, &data);
  933.             break;
  934.                 
  935.         case cProperty:
  936.             propertyCode     = ExtractPropertyCodeFromToken(token);
  937.             objectClass    = ExtractObjectClassFromToken(token);
  938.             if (CanSetProperty(objectClass, propertyCode))
  939.             {
  940.                 error = ExtractKeyDataParameter(appleEvent, &data);
  941.  
  942.                 if (error == noErr)
  943.                     error = SetDataForObject(token, &data);
  944.             }
  945.             else
  946.             {
  947.                 error = errAENotModifiable;
  948.             }
  949.             break;
  950.             
  951.         default:
  952.             error = errAENotModifiable;
  953.             break;
  954.     }
  955.         
  956.     AEDisposeDesc(&data);
  957.     
  958.     return error;
  959. }
  960.  
  961. #pragma mark -
  962. // -----------------------------------------------------------------------------
  963. //                                                Object Accessors
  964. //------------------------------------------------------------------------------
  965. // NOTE: each supported object has 4 accessors installed:
  966. //             object-from-document  : handles "oval 1 of document 2"
  967. //                    object-from-group     : handles "oval 1 of graphic group 2"
  968. //                    object-from-anything  : handles "oval before rectangle 1"
  969. //             property-from-object  : handles "fill color of oval 1"
  970.  
  971. OSErr 
  972. InstallGraphicObjectAccessors(void)
  973. {
  974.  
  975.     OSErr error;
  976.  
  977.     // ----- Graphic Object - a generic handler for all subclasses of cGraphicObject
  978.     
  979.     error = AEInstallObjectAccessor(cGraphicObject, 
  980.                                               cDocument, 
  981.                                               NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  982.                                              0L, 
  983.                                              false);
  984.  
  985.     if (error == noErr)
  986.         error = AEInstallObjectAccessor(cGraphicObject, 
  987.                                                   typeWildCard,             // for formRelativePosition
  988.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  989.                                                   0L, 
  990.                                                   false);
  991.  
  992.     if (error == noErr)
  993.         error = AEInstallObjectAccessor(cGraphicObject, 
  994.                                                   cGroupedGraphic, 
  995.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  996.                                                   0L, 
  997.                                                   false);
  998.     if (error == noErr)
  999.         error = AEInstallObjectAccessor(cProperty, 
  1000.                                                   cGraphicObject, 
  1001.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1002.                                                   0L, 
  1003.                                                   false);    
  1004.     // ----- OVAL
  1005.         
  1006.     if (error == noErr)
  1007.         error = AEInstallObjectAccessor(cOval, 
  1008.                                                   cDocument, 
  1009.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1010.                                                   0L, 
  1011.                                                   false);
  1012.     if (error == noErr)
  1013.         error = AEInstallObjectAccessor(cOval, 
  1014.                                                   typeWildCard,             // for formRelativePosition
  1015.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1016.                                                   0L, 
  1017.                                                   false);
  1018.  
  1019.     if (error == noErr)
  1020.         error = AEInstallObjectAccessor(cOval, 
  1021.                                                   cGroupedGraphic, 
  1022.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1023.                                                   0L, 
  1024.                                                   false);
  1025.  
  1026.     if (error == noErr)
  1027.         error = AEInstallObjectAccessor(cProperty, 
  1028.                                                   cOval, 
  1029.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1030.                                                   0L, 
  1031.                                                   false);
  1032.  
  1033.     // ----- POLYGON
  1034.         
  1035.     if (error == noErr)
  1036.         error = AEInstallObjectAccessor(cPolygon, 
  1037.                                                   cDocument, 
  1038.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1039.                                                   0L, 
  1040.                                                   false);
  1041.  
  1042.     if (error == noErr)
  1043.         error = AEInstallObjectAccessor(cPolygon, 
  1044.                                                   typeWildCard,             // for formRelativePosition
  1045.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1046.                                                   0L, 
  1047.                                                   false);
  1048.  
  1049.     if (error == noErr)
  1050.         error = AEInstallObjectAccessor(cPolygon, 
  1051.                                                   cGroupedGraphic, 
  1052.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1053.                                                   0L, 
  1054.                                                   false);
  1055.  
  1056.     if (error == noErr)
  1057.         error = AEInstallObjectAccessor(cProperty, 
  1058.                                                   cPolygon, 
  1059.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1060.                                                   0L, 
  1061.                                                   false);
  1062.  
  1063.     // ----- RECTANGLES
  1064.         
  1065.     if (error == noErr)
  1066.         error = AEInstallObjectAccessor(cRectangle, 
  1067.                                                   cDocument, 
  1068.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1069.                                                   0L, 
  1070.                                                   false);
  1071.     if (error == noErr)
  1072.         error = AEInstallObjectAccessor(cRectangle, 
  1073.                                                   typeWildCard,             // for formRelativePosition
  1074.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1075.                                                   0L, 
  1076.                                                   false);
  1077.  
  1078.     if (error == noErr)
  1079.         error = AEInstallObjectAccessor(cRectangle, 
  1080.                                                   cGroupedGraphic, 
  1081.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1082.                                                   0L, 
  1083.                                                   false);
  1084.  
  1085.     if (error == noErr)
  1086.         error = AEInstallObjectAccessor(cProperty, 
  1087.                                                   cRectangle, 
  1088.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1089.                                                   0L, 
  1090.                                                   false);
  1091.  
  1092.     // ----- ROUND RECTANGLES
  1093.         
  1094.     if (error == noErr)
  1095.         error = AEInstallObjectAccessor(cRoundedRectangle, 
  1096.                                                   cDocument, 
  1097.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1098.                                                   0L, 
  1099.                                                   false);
  1100.  
  1101.     if (error == noErr)
  1102.         error = AEInstallObjectAccessor(cRoundedRectangle, 
  1103.                                                   typeWildCard,             // for formRelativePosition
  1104.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1105.                                                   0L, 
  1106.                                                   false);
  1107.  
  1108.     if (error == noErr)
  1109.         error = AEInstallObjectAccessor(cRoundedRectangle, 
  1110.                                                   cGroupedGraphic, 
  1111.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1112.                                                   0L, 
  1113.                                                   false);
  1114.  
  1115.     if (error == noErr)
  1116.         error = AEInstallObjectAccessor(cProperty, 
  1117.                                                   cRoundedRectangle, 
  1118.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1119.                                                   0L, 
  1120.                                                   false);
  1121.     
  1122.     // ----- GRAHIC LINE
  1123.         
  1124.     if (error == noErr)
  1125.         error = AEInstallObjectAccessor(cGraphicLine, 
  1126.                                                   cDocument, 
  1127.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1128.                                                   0L, 
  1129.                                                   false);
  1130.  
  1131.     if (error == noErr)
  1132.         error = AEInstallObjectAccessor(cGraphicLine, 
  1133.                                                   typeWildCard,             // for formRelativePosition
  1134.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1135.                                                   0L, 
  1136.                                                   false);
  1137.  
  1138.     if (error == noErr)
  1139.         error = AEInstallObjectAccessor(cGraphicLine, 
  1140.                                                   cGroupedGraphic, 
  1141.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1142.                                                   0L, 
  1143.                                                   false);
  1144.  
  1145.     if (error == noErr)
  1146.         error = AEInstallObjectAccessor(cProperty, 
  1147.                                                   cGraphicLine, 
  1148.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1149.                                                   0L, 
  1150.                                                   false);
  1151.  
  1152.     // --- GROUPED GRAPHICS
  1153.         
  1154.     if (error == noErr)
  1155.         error = AEInstallObjectAccessor(cGroupedGraphic, 
  1156.                                                   cDocument, 
  1157.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1158.                                                   0L, 
  1159.                                                   false);
  1160.  
  1161.     if (error == noErr)
  1162.         error = AEInstallObjectAccessor(cGroupedGraphic, 
  1163.                                                   typeWildCard,             // for formRelativePosition
  1164.                                                   NewOSLAccessorProc(GraphicObjectFromDocumentAccessor), 
  1165.                                                   0L, 
  1166.                                                   false);
  1167.  
  1168.     if (error == noErr)
  1169.         error = AEInstallObjectAccessor(cGroupedGraphic, 
  1170.                                                   cGroupedGraphic, 
  1171.                                                   NewOSLAccessorProc(GraphicObjectFromGroupAccessor), 
  1172.                                                   0L, 
  1173.                                                   false);
  1174.  
  1175.     if (error == noErr)
  1176.         error = AEInstallObjectAccessor(cProperty, 
  1177.                                                   cGroupedGraphic, 
  1178.                                                   NewOSLAccessorProc(PropertyFromGraphicObjectAccessor), 
  1179.                                                   0L, 
  1180.                                                   false);
  1181.  
  1182.     return error;
  1183. }
  1184.  
  1185.  
  1186. #pragma mark -
  1187. //------------------------------------------------------------------------------
  1188. //                                    Graphic Object From Document Accessor
  1189. //------------------------------------------------------------------------------
  1190. //    Retrieve any generic graphic object from a Document container by the key form
  1191.  
  1192. static pascal OSErr 
  1193. GraphicObjectFromDocumentAccessor(
  1194.                     DescType        desiredClass,            // any subclass of cGraphicObject
  1195.             const AEDesc*        containerToken,
  1196.                     DescType        containerClass,
  1197.                     DescType        keyForm,
  1198.             const AEDesc*        keyData,
  1199.                     AEDesc*        resultToken,        // specified object is returned in result
  1200.                     long             refcon   )
  1201. {
  1202.     DocumentReference    document;
  1203.     ElementList         list;
  1204.     OSErr                 error;     
  1205.     
  1206.     error = GetDocumentReferenceFromToken(containerToken, &document);
  1207.     
  1208.     if (error == noErr && document != nil)
  1209.     {
  1210.         list = GetDocumentElementList(document);
  1211.         if (list == nil)
  1212.             error = errAENoSuchObject;
  1213.     }
  1214.     
  1215.     if (error == noErr)
  1216.         error = GraphicObjectAccessor(list, desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refcon);
  1217.     
  1218.     return error;
  1219. }    
  1220.  
  1221. //------------------------------------------------------------------------------
  1222. //                                    Graphic Object From Group Accessor
  1223. //------------------------------------------------------------------------------
  1224.  
  1225. static pascal OSErr 
  1226. GraphicObjectFromGroupAccessor(    
  1227.                 DescType        desiredClass,
  1228.         const AEDesc*        containerToken,
  1229.                 DescType        containerClass,
  1230.                 DescType        keyForm,
  1231.         const AEDesc*        keyData,
  1232.                 AEDesc*        resultToken,
  1233.                 long             refcon)
  1234. {
  1235.     OSErr                    error;    
  1236.     DocumentReference    document           = nil;
  1237.     ElementReference  element        = nil;
  1238.     ElementList            list                 = nil;
  1239.     
  1240.     error = GetDocumentReferenceFromToken(containerToken, &document);
  1241.  
  1242.     if (error == noErr)
  1243.         error = GetElementReferenceFromToken(containerToken, &element);
  1244.         
  1245.     if (error == noErr)
  1246.     {
  1247.         list = GetSubElementList(element);
  1248.         if (list == nil)
  1249.             error = errAENoSuchObject;
  1250.     }
  1251.     
  1252.     if (error == noErr)
  1253.         error = GraphicObjectAccessor(list, desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refcon);
  1254.  
  1255.     return error;
  1256. }
  1257.  
  1258. //------------------------------------------------------------------------------
  1259. //                                    Graphic Object From Document Accessor
  1260. //    Retrieve any graphic object from a the element list 
  1261. // of the specified container by the specified key form
  1262. //------------------------------------------------------------------------------
  1263.  
  1264. static pascal OSErr 
  1265. GraphicObjectAccessor(               
  1266.                 ElementList list,
  1267.                 DescType        desiredClass,        // any subclass of cGraphicObject
  1268.         const AEDesc*        containerToken,
  1269.                 DescType        containerClass,
  1270.                 DescType        keyForm,
  1271.         const AEDesc*        keyData,
  1272.                 AEDesc*        resultToken,        // specified object is returned in result
  1273.                 long             refcon   )
  1274. {
  1275.     #pragma unused (containerClass, refcon)
  1276.  
  1277.     OSErr                    error                = noErr;    
  1278.  
  1279.     DocumentReference    document           = nil;
  1280.  
  1281.     long                    elementNumber  = 0L;
  1282.     ElementReference  element        = nil;
  1283.     ElementType            elementType;
  1284.  
  1285.     DescType                keyDataType     = keyData->descriptorType;
  1286.     long                    index;
  1287.     long                    numElements;
  1288.     Boolean                wantsAllItems    = false;
  1289.  
  1290.     AEDesc                 startObject     =    {typeNull, nil};    // These are used to resolve formRange
  1291.     AEDesc                 stopObject        =     {typeNull, nil};
  1292.         
  1293.     CoreTokenRecord     token;
  1294.     InitCoreTokenRecord(&token);
  1295.     
  1296.     error = GetDocumentReferenceFromToken(containerToken, &document);
  1297.     if (error != noErr)
  1298.         goto CleanUp;
  1299.     
  1300.     numElements = CountElementsByClass(list, desiredClass);
  1301.     
  1302.     switch (keyForm) 
  1303.     {        
  1304.         case formUniqueID:
  1305.             if (keyDataType == typeLongInteger)
  1306.             {
  1307.                 long uniqueID;
  1308.                 
  1309.                 if (DescToLong(keyData, &uniqueID) != noErr)
  1310.                 {
  1311.                     error = errAECoercionFail;
  1312.                 }
  1313.                 else
  1314.                 {
  1315.                     element = FindElementByUniqueID(list, uniqueID);
  1316.                     if (element == nil)
  1317.                         error = errAENoSuchObject;
  1318.                     else if (desiredClass != cGraphicObject)
  1319.                     {
  1320.                         // Make sure the element with that ID is really an element of the desired class
  1321.  
  1322.                         ElementType elementType = GetElementType(element);
  1323.                         DescType        objectClass;
  1324.                         ConvertElementTypeToObjectClass(elementType, &objectClass);
  1325.                         if (desiredClass != objectClass)
  1326.                             error = errAENoSuchObject;
  1327.                     }
  1328.                 }
  1329.             }
  1330.             else
  1331.             {
  1332.                 error = errAEWrongDataType;
  1333.             }
  1334.             break;
  1335.         
  1336.         case formAbsolutePosition:
  1337.             error = NormalizeAbsoluteIndex(keyData, &index, numElements, &wantsAllItems);
  1338.             if ((error == noErr) && (wantsAllItems == false))
  1339.             {
  1340.                 error = FindElementByIndex(list, desiredClass, index, &element);
  1341.            }
  1342.             break;    
  1343.         
  1344.         case formRelativePosition:
  1345.             error = ProcessFormRelativePostition(containerToken, keyData, desiredClass, &element);
  1346.             break;    
  1347.         
  1348.         case formRange:
  1349.             switch (keyDataType)
  1350.             {        
  1351.                 case typeRangeDescriptor:
  1352.                     error = ProcessFormRange((AEDesc *)keyData, &startObject, &stopObject);
  1353.                     if (error == noErr)
  1354.                     {
  1355.                         DescType startType = ExtractDispatchClassFromToken(&startObject);
  1356.                         DescType stopType  = ExtractDispatchClassFromToken(&stopObject);
  1357.      
  1358.                         if (startType != cGraphicObject || stopType != cGraphicObject)
  1359.                             error = errAEWrongDataType;
  1360.                     }
  1361.                     break;
  1362.  
  1363.                 default:
  1364.                     error = errAEWrongDataType;
  1365.                     break;    
  1366.             }
  1367.             break;    
  1368.         
  1369.         default:
  1370.             return errAEEventNotHandled;
  1371.     }
  1372.     
  1373.     // if user asked for all items, and there aren't any,
  1374.     // we'll be kind and return an empty list.
  1375.  
  1376.     if (wantsAllItems && (error == errAENoSuchObject || error == errAEIllegalIndex))
  1377.     {
  1378.         error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  1379.         goto CleanUp;
  1380.     }
  1381.  
  1382.     // fill in the result token
  1383.  
  1384.     if (error == noErr)
  1385.     {
  1386.         token.dispatchClass   = cGraphicObject;
  1387.         token.objectClass         = cGraphicObject;
  1388.         token.propertyCode    = typeNull;
  1389.         token.documentNumber     = GetDocumentNumber(document);
  1390.  
  1391.         if (wantsAllItems)
  1392.         {
  1393.             error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  1394.             
  1395.             if (error == noErr)
  1396.             {
  1397.                 for (index = 1; index <= numElements; index++)
  1398.                 {
  1399.                     error = FindElementByIndex(list, desiredClass, index, &element);
  1400.                     if (error != noErr)
  1401.                         goto CleanUp;
  1402.                     
  1403.                     token.elementNumber = GetElementNumber(element);
  1404.  
  1405.                     error = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
  1406.                     if (error != noErr)
  1407.                         goto CleanUp;
  1408.                 }
  1409.             }
  1410.         }
  1411.         else if (keyForm == formRange)
  1412.         {            
  1413.             ElementReference    beginElement;
  1414.             ElementReference  endElement;
  1415.             ElementType            desiredType;
  1416.             
  1417.             long                    beginIndex;
  1418.             long                    endIndex;
  1419.  
  1420.             ConvertObjectClassToElementType(desiredClass, &desiredType);
  1421.             
  1422.             error = GetElementReferenceFromToken(&startObject, &beginElement);
  1423.             if (error != noErr)
  1424.                 goto CleanUp;
  1425.             beginIndex = GetIndexForElementType(document, beginElement, (ElementType)typeWildCard);
  1426.  
  1427.             error = GetElementReferenceFromToken(&stopObject, &endElement);
  1428.             if (error != noErr)
  1429.                 goto CleanUp;
  1430.             endIndex = GetIndexForElementType(document, endElement, (ElementType)typeWildCard);
  1431.                                     
  1432.             error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  1433.             if (error != noErr)
  1434.                 goto CleanUp;
  1435.                 
  1436.             if (beginIndex > endIndex) // swap elements
  1437.             {
  1438.                 ElementReference temp;
  1439.                 
  1440.                 temp                 = beginElement;
  1441.                 beginElement     = endElement;
  1442.                 endElement       = temp;
  1443.             }
  1444.             
  1445.             element = beginElement;
  1446.             while (element != nil)
  1447.             {
  1448.                 elementType = GetElementType(element);
  1449.                 if (desiredClass == cGraphicObject || elementType == desiredType)
  1450.                 {
  1451.                     token.elementNumber = GetElementNumber(element);
  1452.                 
  1453.                     error = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
  1454.                     if (error != noErr)
  1455.                         goto CleanUp;
  1456.                 }
  1457.                 if (element == endElement)
  1458.                     break;
  1459.                 element = GetPreviousElement(element); // because the 1st object is at the end of the list
  1460.             }
  1461.         }
  1462.         else
  1463.         {
  1464.             token.elementNumber = GetElementNumber(element);
  1465.               error = AECreateDesc(desiredClass, &token, sizeof(token), resultToken);
  1466.         }
  1467.     }
  1468.  
  1469. CleanUp:
  1470.     
  1471.     AEDisposeDesc(&startObject);
  1472.     AEDisposeDesc(&stopObject);
  1473.         
  1474.     return error;
  1475. }
  1476.  
  1477. #pragma mark -
  1478. //----------------------------------------------------------------------------------
  1479. //                                        Graphic Object Property Accessor
  1480. //----------------------------------------------------------------------------------
  1481. // Handles properties from ANY graphic object or subclass of cGraphicObject
  1482. //
  1483. // NOTE: The container can be either a single token, or a list of tokens
  1484. // 
  1485. //----------------------------------------------------------------------------------
  1486.  
  1487. pascal OSErr 
  1488. PropertyFromGraphicObjectAccessor(     DescType        desiredClass,
  1489.                                  const AEDesc*        containerToken,
  1490.                                          DescType        containerClass,
  1491.                                          DescType        keyForm,
  1492.                                 const AEDesc*        keyData,
  1493.                                          AEDesc*        resultToken,
  1494.                                          long             refcon)
  1495. {
  1496.     OSErr    error;
  1497.  
  1498.     if (containerToken->descriptorType != typeAEList)
  1499.     {
  1500.         error = PropertyFromObjectAccessor(desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refcon);
  1501.     }
  1502.     else
  1503.     {
  1504.         error = AECreateList(NULL, 0L, false, resultToken);
  1505.         if (error == noErr)
  1506.             error = PropertyFromListAccessor(desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refcon);
  1507.     }
  1508.     
  1509.     return error;
  1510. }
  1511.  
  1512. //----------------------------------------------------------------------------------
  1513.  
  1514. static OSErr 
  1515. PropertyFromListAccessor(
  1516.                                          DescType        desiredClass,
  1517.                                  const AEDesc*        containerToken,
  1518.                                          DescType        containerClass,
  1519.                                          DescType        keyForm,
  1520.                                 const AEDesc*        keyData,
  1521.                                          AEDesc*        resultToken,
  1522.                                          long             refcon)
  1523. {
  1524.     OSErr            error        = noErr;
  1525.     long            index;
  1526.     long            numItems;
  1527.     DescType        keyword;
  1528.     AEDesc        srcItem     = {typeNull, nil};
  1529.     AEDesc        dstItem     = {typeNull, nil};
  1530.     
  1531.     error = AECountItems((AEDescList*)containerToken, &numItems);
  1532.     if (error != noErr)
  1533.         goto CleanUp;
  1534.         
  1535.     for (index = 1; index <= numItems; index++)
  1536.     {
  1537.        error = AEGetNthDesc(containerToken, index, typeWildCard, &keyword, &srcItem);
  1538.         if (error != noErr)
  1539.             goto CleanUp;
  1540.         
  1541.         if (srcItem.descriptorType != typeAEList)
  1542.         {
  1543.             error = PropertyFromObjectAccessor(desiredClass, &srcItem, containerClass, keyForm, keyData, &dstItem, refcon);
  1544.         }
  1545.         else
  1546.         {
  1547.             error = AECreateList(NULL, 0L, false, &dstItem);
  1548.             if (error == noErr)
  1549.                 error = PropertyFromListAccessor(desiredClass, &srcItem, containerClass, keyForm, keyData, &dstItem, refcon);
  1550.         }
  1551.         
  1552.         if (error != noErr)
  1553.             goto CleanUp;
  1554.  
  1555.         error = AEPutDesc(resultToken, index, &dstItem);
  1556.         if (error != noErr)
  1557.             goto CleanUp;
  1558.                 
  1559.         AEDisposeDesc(&srcItem);
  1560.         AEDisposeDesc(&dstItem);
  1561.     }
  1562.     
  1563. CleanUp:
  1564.  
  1565.     AEDisposeDesc(&srcItem);
  1566.     AEDisposeDesc(&dstItem);
  1567.  
  1568.     return error;
  1569. }
  1570.  
  1571. // ----------------------------------------------------------------------------
  1572.  
  1573. static OSErr 
  1574. PropertyFromObjectAccessor(DescType        desiredType,            // cProperty
  1575.                                 const     AEDesc*        containerToken,        // single container, or typeAEList of containers
  1576.                                           DescType        containerClass,        // any subclass of cGraphicObject
  1577.                                           DescType        keyForm,                    // formPropertyID
  1578.                               const    AEDesc*        keyData,                    // dataHandle points to which property
  1579.                                           AEDesc*        resultToken,
  1580.                                           long             refcon     )
  1581. {
  1582.     #pragma unused (keyForm, refcon)
  1583.  
  1584.     OSErr                        error = noErr;
  1585.     DescType                    requestedProperty = **(DescType**)(keyData->dataHandle);
  1586.         
  1587.     if (CanGetProperty(containerClass, requestedProperty) || CanSetProperty(containerClass, requestedProperty))
  1588.     {
  1589.         error = AEDuplicateDesc(containerToken, resultToken);
  1590.  
  1591.         if (error == noErr)
  1592.         {
  1593.             resultToken->descriptorType = desiredType;
  1594.             (**(CoreTokenHandle)(resultToken->dataHandle)).propertyCode    = requestedProperty;
  1595.             (**(CoreTokenHandle)(resultToken->dataHandle)).objectClass     = containerClass;
  1596.         }
  1597.     }
  1598.     else
  1599.     {
  1600.         error = errAEEventNotHandled;
  1601.     }
  1602.     
  1603.     return error;
  1604. }
  1605.  
  1606. #pragma mark -
  1607.  
  1608. // -------------------------------------------------------------------------------------------
  1609. //
  1610. //   GetDataFromGraphicObject
  1611. //
  1612. // Given a token that contains information about a graphic object, access the graphic object
  1613. // to extract the relevant data, and return it to the caller in the "data" parameter.
  1614. //
  1615. // PUBLIC: also called from the ObjectComparison callback function
  1616. //
  1617. // The first parameter contains either a single token or a list of tokens
  1618. // The second parameter is NULL or a list of preferred types for the return data
  1619. //
  1620. // -------------------------------------------------------------------------------------------
  1621.  
  1622. OSErr
  1623. GetDataFromGraphicObject(AEDesc *tokenOrTokenList, AEDesc *desiredTypes, AEDesc *data)
  1624. {
  1625.     OSErr error = noErr;
  1626.     
  1627.     if (tokenOrTokenList->descriptorType != typeAEList)
  1628.     {
  1629.         error = GetDataFromObject(tokenOrTokenList, desiredTypes, data);
  1630.     }
  1631.     else
  1632.     {
  1633.         error = AECreateList(NULL, 0L, false, data);
  1634.         if (error == noErr)
  1635.             error = GetDataFromList(tokenOrTokenList, desiredTypes, data);
  1636.     }
  1637.     
  1638.     return error;
  1639. }
  1640.  
  1641. // -------------------------------------------------------------------------------------------
  1642. //
  1643. //   GetDataFromList
  1644. //
  1645. //      Given a list of objects, replicate the list structure and replace the tokens
  1646. //   with a list of the requested data from each token
  1647. //
  1648. // -------------------------------------------------------------------------------------------
  1649.  
  1650. static OSErr
  1651. GetDataFromList(AEDesc *srcList, AEDesc *desiredTypes, AEDesc *dstList)
  1652. {
  1653.     OSErr            error        = noErr;
  1654.     long            index;
  1655.     long            numItems;
  1656.     DescType        keyword;
  1657.     AEDesc        srcItem     = {typeNull, nil};
  1658.     AEDesc        dstItem     = {typeNull, nil};
  1659.         
  1660.     error = AECountItems((AEDescList*)srcList, &numItems);
  1661.     if (error != noErr)
  1662.         goto CleanUp;
  1663.         
  1664.     for (index = 1; index <= numItems; index++)
  1665.     {
  1666.        error = AEGetNthDesc(srcList, index, typeWildCard, &keyword, &srcItem);
  1667.         if (error != noErr)
  1668.             goto CleanUp;
  1669.         
  1670.         if (srcItem.descriptorType != typeAEList)
  1671.         {
  1672.             error = GetDataFromObject(&srcItem, desiredTypes, &dstItem);  // Get data from single item
  1673.         }
  1674.         else
  1675.         {
  1676.             error = AECreateList(NULL, 0L, false, &dstItem);
  1677.             if (error == noErr)
  1678.                 error = GetDataFromList(&srcItem, desiredTypes, &dstItem);
  1679.         }
  1680.         if (error != noErr)
  1681.             goto CleanUp;
  1682.  
  1683.         error = AEPutDesc(dstList, index, &dstItem);
  1684.         if (error != noErr)
  1685.             goto CleanUp;
  1686.                 
  1687.         AEDisposeDesc(&srcItem);
  1688.         AEDisposeDesc(&dstItem);
  1689.     }
  1690.     
  1691. CleanUp:
  1692.  
  1693.     AEDisposeDesc(&srcItem);
  1694.     AEDisposeDesc(&dstItem);
  1695.  
  1696.     return error;
  1697. }
  1698.  
  1699. //----------------------------------------------------------------------------------
  1700. //                                       GetDataFromObject
  1701. //  Get the data from one object
  1702. //----------------------------------------------------------------------------------
  1703.  
  1704. static OSErr    
  1705. GetDataFromObject(AEDesc *token, AEDesc *desiredTypes, AEDesc *data)
  1706. {
  1707.     OSErr                    error            = noErr;
  1708.     
  1709.     DocumentReference document     = nil;
  1710.     ElementReference  element     = nil;
  1711.     
  1712.     ElementType            elementType;
  1713.     DescType                objectClass;
  1714.     DescType                propertyCode;
  1715.     
  1716.     Handle                textH            = nil;
  1717.     char                  *text            = NULL;
  1718.     
  1719.     long                    aLong;
  1720.     short                    aShort;
  1721.     Rect                    aRect;
  1722.     Point                    aPoint;
  1723.     short double        aShortDouble;
  1724.     
  1725.     RGBColor                aRGBColor;
  1726.     ColorRecord            aColor;
  1727.     Boolean                foundIt;
  1728.                 
  1729.     DescType                mostDesiredType = typeNull;
  1730.     
  1731.     error = GetDocumentReferenceFromToken(token, &document);
  1732.     if (error != noErr)
  1733.         goto CleanUp;
  1734.  
  1735.     error = GetElementReferenceFromToken(token, &element);
  1736.     if (error != noErr)
  1737.         goto CleanUp;
  1738.         
  1739.     elementType  = GetElementType(element);
  1740.     
  1741.     propertyCode = ExtractPropertyCodeFromToken(token);
  1742.     
  1743.     ConvertElementTypeToObjectClass(elementType, &objectClass);
  1744.     
  1745.     if (desiredTypes != NULL && desiredTypes->descriptorType != typeNull)
  1746.     {
  1747.         long            numItems;
  1748.         AEKeyword    keyword;
  1749.         DescType        actualType;
  1750.         long            actualSize;
  1751.         
  1752.         error = AECountItems(desiredTypes, &numItems);
  1753.         if (error == noErr)
  1754.         {
  1755.             error = AEGetNthPtr(desiredTypes, 1L, typeType, &keyword, &actualType, &mostDesiredType, sizeof(DescType), &actualSize);
  1756.         }
  1757.     }
  1758.     
  1759.     switch (propertyCode)
  1760.     {
  1761.         // -------------------------------------------------------------------------------
  1762.         //  Base object properties
  1763.         // -------------------------------------------------------------------------------
  1764.  
  1765.         case pBestType:
  1766.         case pClass:
  1767.         case pDefaultType:
  1768.         case pObjectType:
  1769.             error = AECreateDesc(typeType, &objectClass, sizeof(DescType), data);
  1770.             break;
  1771.  
  1772.         case pProperties:
  1773.             {                
  1774.                 error = AECreateList(NULL, 0L, true, data);
  1775.                 if (error != noErr)
  1776.                     goto CleanUp;
  1777.                     
  1778.                 // now, add each property to the above record
  1779.                 
  1780.                 error = AEPutKeyPtr(data, pObjectType, typeType, &objectClass, sizeof(DescType));
  1781.  
  1782.                 aLong = GetElementNumber(element);
  1783.                 error = AEPutKeyPtr(data, pID, typeLongInteger, &aLong, sizeof(long));
  1784.                                                 
  1785.                 aRect = GetElementBoundingBox(element);
  1786.                 error = AEPutKeyPtr(data, pBounds, typeQDRectangle, &aRect, sizeof(Rect));
  1787.                 
  1788.                 aPoint = topLeft(aRect); // NOTE: depends on the GetElementBoundingBox directly above!!!
  1789.                 error = AEPutKeyPtr(data, pLocation, typeQDPoint, &aPoint, sizeof(Point));
  1790.                 
  1791.                 aShort = aRect.right - aRect.left;
  1792.                 error = AEPutKeyPtr(data, pWidth,  typeShortInteger, &aShort, sizeof(short));
  1793.                 
  1794.                 aShort = aRect.bottom - aRect.top;
  1795.                 error = AEPutKeyPtr(data, pHeight, typeShortInteger, &aShort, sizeof(short));
  1796.                 
  1797.                 // stroke props
  1798.                 
  1799.                 aShortDouble = (short double)GetElementStrokePenWidth(element);
  1800.                 error = AEPutKeyPtr(data, pStrokeSize, typeFloat, &aShortDouble, sizeof(short double));
  1801.  
  1802.                 aRGBColor = GetElementStrokeColor(element);
  1803.                 foundIt = GetColorRecordByRGB(aRGBColor, &aColor);
  1804.                 if (foundIt)
  1805.                     error = AEPutKeyPtr(data, pStrokeColor, typeEnumerated, &aColor.code, sizeof(DescType));
  1806.                 else
  1807.                     error = AEPutKeyPtr(data, pStrokeColor, typeRGBColor, &aRGBColor, sizeof(RGBColor));
  1808.                     
  1809.                 // fill props
  1810.                 
  1811.                 aRGBColor = GetElementFillColor(element);
  1812.                 foundIt = GetColorRecordByRGB(aRGBColor, &aColor);
  1813.                 if (foundIt)
  1814.                     error = AEPutKeyPtr(data, pFillColor, typeEnumerated, &aColor.code, sizeof(DescType));
  1815.                 else
  1816.                     error = AEPutKeyPtr(data, pFillColor, typeRGBColor, &aRGBColor, sizeof(RGBColor));
  1817.                     
  1818.                 // Polygons only
  1819.                 
  1820.                 if (elementType == kQDPolygon)
  1821.                 {
  1822.                     AEDesc pointList = {typeNull, nil};
  1823.                     
  1824.                     // Extract the points from the polygon and build a typeAEList object
  1825.                     
  1826.                     error = AECreateList(nil, (Size)0, false, &pointList);             // create an empty list to hold the Points
  1827.                     
  1828.                     if (error == noErr)
  1829.                     {
  1830.                         PolyHandle polyHandle = GetElementPolygon(element);
  1831.                         if (polyHandle != nil)
  1832.                         {
  1833.                             short numPoints = CountPolygonPoints(polyHandle);
  1834.                             short pointNum;
  1835.                             
  1836.                             for (pointNum = 1; pointNum <= numPoints; pointNum++)
  1837.                             {
  1838.                                 aPoint = GetPolygonPoint(polyHandle, pointNum);
  1839.                                 error     = AEPutPtr(&pointList, pointNum, typeQDPoint, &aPoint, sizeof(Point));
  1840.                                 if (error != noErr)
  1841.                                     goto CleanUp;
  1842.                             }
  1843.                         }
  1844.                     }
  1845.                     
  1846.                     if (error == noErr)
  1847.                         error = AEPutKeyDesc(data, pPointList, &pointList);
  1848.                         
  1849.                     AEDisposeDesc(&pointList);
  1850.                 }
  1851.                 
  1852.                 // Rounded Rects only
  1853.                 
  1854.                 if (elementType == kQDRoundRect)
  1855.                 {
  1856.                     aShort = GetElementRoundRectOvalSize(element).v;
  1857.                     error = AEPutKeyPtr(data, pCornerCurveHeight, typeShortInteger, &aShort, sizeof(short));
  1858.  
  1859.                     aShort = GetElementRoundRectOvalSize(element).h;
  1860.                     error = AEPutKeyPtr(data, pCornerCurveWidth, typeShortInteger, &aShort, sizeof(short));
  1861.                 }
  1862.                 
  1863.                 // Graphic Line only
  1864.                 
  1865.                 if (elementType == kQDLine)
  1866.                 {
  1867.                     aPoint = GetElementLineBeginPoint(element);
  1868.                     error = AEPutKeyPtr(data, pStartPoint, typeQDPoint, &aPoint, sizeof(Point));
  1869.                     
  1870.                     aPoint = GetElementLineBeginPoint(element);
  1871.                     error = AEPutKeyPtr(data, pStartPoint, typeQDPoint, &aPoint, sizeof(Point));
  1872.                 }
  1873.             }
  1874.             break;
  1875.  
  1876.         case pContents:
  1877.             switch (elementType)
  1878.             {                    
  1879.                 case kGroup:
  1880.                     {
  1881.                         ElementList         list = GetSubElementList(element);
  1882.                         ElementReference     subElement;
  1883.                         AEDesc                subElementOSpec = {typeNull, nil};
  1884.                         
  1885.                         if (list == nil)
  1886.                             error = errAENoSuchObject;
  1887.                         
  1888.                         if (error == noErr)
  1889.                             error = AECreateList(NULL, 0L, false, data);
  1890.                             
  1891.                         if (error == noErr)
  1892.                         {
  1893.                             for (subElement = GetFirstElement(list); subElement != nil; subElement = GetNextElement(subElement))
  1894.                             {
  1895.                                 error = CreateGraphicGroupMemberOSpec(document, element, subElement, &subElementOSpec);
  1896.                                 if (error != noErr)
  1897.                                     break;
  1898.                                     
  1899.                                 error = AEPutDesc(data, 0L, &subElementOSpec);
  1900.                                 if (error != noErr)
  1901.                                     break;
  1902.                                 
  1903.                                 AEDisposeDesc(&subElementOSpec);
  1904.                             }
  1905.                         }
  1906.                         
  1907.                         if (error != noErr)
  1908.                             AEDisposeDesc(data);
  1909.                             
  1910.                         AEDisposeDesc(&subElementOSpec);
  1911.                     }
  1912.                     break;
  1913.  
  1914.                 default:
  1915.                     error = errAECantSupplyType;
  1916.                     break;
  1917.             }
  1918.             break;
  1919.  
  1920.         // -------------------------------------------------------------------------------
  1921.         //     Graphic object properties
  1922.         // -------------------------------------------------------------------------------
  1923.  
  1924.         case pID:
  1925.             aLong = GetElementNumber(element);
  1926.             error = AECreateDesc(typeLongInteger, &aLong, sizeof(long), data);        
  1927.             break;
  1928.                         
  1929.         case pBounds:
  1930.             aRect = GetElementBoundingBox(element);
  1931.             error = AECreateDesc(typeQDRectangle, &aRect, sizeof(Rect), data);
  1932.             break;
  1933.             
  1934.         case pLocation:
  1935.             aRect = GetElementBoundingBox(element);
  1936.             aPoint = topLeft(aRect);
  1937.             error = AECreateDesc(typeQDPoint, &aPoint, sizeof(Point), data);
  1938.             break;
  1939.             
  1940.         case pWidth:
  1941.             aRect  = GetElementBoundingBox(element);
  1942.             aShort = aRect.right - aRect.left;
  1943.             error  = AECreateDesc(typeShortInteger, &aShort, sizeof(short), data);
  1944.             break;
  1945.             
  1946.         case pHeight:
  1947.             aRect  = GetElementBoundingBox(element);
  1948.             aShort = aRect.bottom - aRect.top;
  1949.             error = AECreateDesc(typeShortInteger, &aShort, sizeof(short), data);
  1950.             break;
  1951.                         
  1952.         // -------------------------------------------------------------------------------
  1953.         // Stroke
  1954.         // -------------------------------------------------------------------------------
  1955.         
  1956.         case pStrokeSize:
  1957.             aShortDouble    = (short double)GetElementStrokePenWidth(element);
  1958.             error = AECreateDesc(typeFloat, &aShortDouble, sizeof(short double), data);                
  1959.             break;
  1960.             
  1961.         case pStrokeColor:
  1962.             aRGBColor = GetElementStrokeColor(element);
  1963.             
  1964.             foundIt = GetColorRecordByRGB(aRGBColor, &aColor);
  1965.                             
  1966.             switch (mostDesiredType)
  1967.             {
  1968.                 case typeEnumerated:
  1969.                 case typeType:
  1970.                     if (foundIt)
  1971.                         error = AECreateDesc(typeEnumerated, &aColor.code, sizeof(DescType), data);
  1972.                     else
  1973.                         error = errAECantSupplyType;
  1974.                     break;
  1975.                 
  1976.                 case typeChar:
  1977.                 case typeIntlText:
  1978.                     if (foundIt)
  1979.                         error = AECreateDesc(typeChar, aColor.name, strlen(aColor.name), data);
  1980.                     else
  1981.                         error = errAECantSupplyType;
  1982.                     break;
  1983.                                         
  1984.                 default:
  1985.                 case typeNull:
  1986.                 case typeWildCard:
  1987.                 case typeBest:
  1988.                 case typeRGBColor:
  1989.                     error = AECreateDesc(typeRGBColor, &aRGBColor, sizeof(RGBColor), data);
  1990.                     break;
  1991.             }
  1992.             break;
  1993.                         
  1994.         // -------------------------------------------------------------------------------
  1995.         // Fill 
  1996.         // -------------------------------------------------------------------------------
  1997.         
  1998.         case pFillColor:
  1999.             aRGBColor = GetElementFillColor(element);
  2000.             foundIt   = GetColorRecordByRGB(aRGBColor, &aColor);
  2001.                             
  2002.             switch (mostDesiredType)
  2003.             {
  2004.                 case typeEnumerated:
  2005.                 case typeType:
  2006.                     if (foundIt)
  2007.                         error = AECreateDesc(typeEnumerated, &aColor.code, sizeof(DescType), data);
  2008.                     else
  2009.                         error = errAECantSupplyType;
  2010.                     break;
  2011.                 
  2012.                 case typeChar:
  2013.                 case typeIntlText:
  2014.                     if (foundIt)
  2015.                         error = AECreateDesc(typeChar, aColor.name, strlen(aColor.name), data);
  2016.                     else
  2017.                         error = errAECantSupplyType;
  2018.                     break;
  2019.                                         
  2020.                 default:
  2021.                 case typeNull:
  2022.                 case typeWildCard:
  2023.                 case typeBest:
  2024.                 case typeRGBColor:
  2025.                     error = AECreateDesc(typeRGBColor, &aRGBColor, sizeof(RGBColor), data);
  2026.                     break;
  2027.             }
  2028.                         
  2029.             break;
  2030.             
  2031.         // -------------------------------------------------------------------------------
  2032.         // for cPolygon only
  2033.         // -------------------------------------------------------------------------------
  2034.         
  2035.         case pPointList:
  2036.             if (GetElementType(element) != kQDPolygon)
  2037.             {
  2038.                 error = errAECantSupplyType;
  2039.                 break;
  2040.             }
  2041.                 
  2042.             // Extract the points from the polygon and build a typeAEList object
  2043.             
  2044.             error = AECreateList(nil, (Size)0, false, data);             // create an empty list to hold the Points
  2045.             if (error == noErr)
  2046.             {
  2047.                 PolyHandle polyHandle = GetElementPolygon(element);
  2048.                 if (polyHandle != nil)
  2049.                 {
  2050.                     short numPoints = CountPolygonPoints(polyHandle);
  2051.                     short pointNum;
  2052.                     
  2053.                     for (pointNum = 1; error == noErr && pointNum <= numPoints; pointNum++)
  2054.                     {
  2055.                         aPoint = GetPolygonPoint(polyHandle, pointNum);
  2056.                         error  = AEPutPtr(data, pointNum, typeQDPoint, &aPoint, sizeof(Point));
  2057.                     }
  2058.                 }
  2059.             }
  2060.             break;
  2061.             
  2062.         // -------------------------------------------------------------------------------
  2063.         // for cRoundedRectangle only
  2064.         // -------------------------------------------------------------------------------
  2065.         
  2066.         case pCornerCurveHeight:
  2067.             if (GetElementType(element) != kQDRoundRect)
  2068.             {
  2069.                 error = errAECantSupplyType;
  2070.                 break;
  2071.             }
  2072.             aShort = GetElementRoundRectOvalSize(element).v;
  2073.             error = AECreateDesc(typeShortInteger, &aShort, sizeof(short), data);        
  2074.             break;        
  2075.             
  2076.         case pCornerCurveWidth:
  2077.             if (GetElementType(element) != kQDRoundRect)
  2078.             {
  2079.                 error = errAECantSupplyType;
  2080.                 break;
  2081.             }
  2082.             aShort = GetElementRoundRectOvalSize(element).h;
  2083.             error = AECreateDesc(typeShortInteger, &aShort, sizeof(short), data);        
  2084.             break;                    
  2085.             
  2086.         // -------------------------------------------------------------------------------
  2087.         // for cGraphicLine only (also uses pen items above)
  2088.         // -------------------------------------------------------------------------------
  2089.     
  2090.         case pStartPoint:
  2091.             if (GetElementType(element) != kQDLine)
  2092.             {
  2093.                 error = errAECantSupplyType;
  2094.                 break;
  2095.             }
  2096.             aPoint = GetElementLineBeginPoint(element);
  2097.             error = AECreateDesc(typeQDPoint, &aPoint, sizeof(Point), data);    
  2098.             break;    
  2099.  
  2100.         case pEndPoint:
  2101.             if (GetElementType(element) != kQDLine)
  2102.             {
  2103.                 error = errAECantSupplyType;
  2104.                 break;
  2105.             }
  2106.  
  2107.             aPoint = GetElementLineBeginPoint(element);
  2108.             error = AECreateDesc(typeQDPoint, &aPoint, sizeof(Point), data);    
  2109.             break;    
  2110.                             
  2111.             
  2112.         // -------------------------------------------------------------------------------
  2113.         // for cGroupedGraphic only
  2114.         // -------------------------------------------------------------------------------
  2115.         
  2116.         case pGraphicObjects:
  2117.             // Returns a list of ospec records for the objects in the group,
  2118.             // with the frontmost object first, etc.
  2119.             if (GetElementType(element) != kGroup)
  2120.             {
  2121.                 error = errAECantSupplyType;
  2122.                 break;
  2123.             }
  2124.                 
  2125.             // Build a typeAEList object containing references to the objects
  2126.             
  2127.             error = AECreateList(nil, (Size)0, false, data);             // create an empty list to hold the Points
  2128.             if (error == noErr)
  2129.             {
  2130.                 ElementList         list = GetSubElementList(element);
  2131.                 ElementReference     subElement;
  2132.                 AEDesc                subElementOSpec = {typeNull, nil};
  2133.                 
  2134.                 if (list == nil)
  2135.                     error = errAENoSuchObject;
  2136.                 
  2137.                 if (error == noErr)
  2138.                     error = AECreateList(NULL, 0L, false, data);
  2139.                     
  2140.                 if (error == noErr)
  2141.                 {
  2142.                     for (subElement = GetFirstElement(list); subElement != nil; subElement = GetNextElement(subElement))
  2143.                     {
  2144.                         error = CreateGraphicGroupMemberOSpec(document, element, subElement, &subElementOSpec);
  2145.                         if (error != noErr)
  2146.                             break;
  2147.                             
  2148.                         error = AEPutDesc(data, 0L, &subElementOSpec);
  2149.                         if (error != noErr)
  2150.                             break;
  2151.                         
  2152.                         AEDisposeDesc(&subElementOSpec);
  2153.                     }
  2154.                 }
  2155.                 
  2156.                 if (error != noErr)
  2157.                     AEDisposeDesc(data);
  2158.                     
  2159.                 AEDisposeDesc(&subElementOSpec);
  2160.             }
  2161.             break;
  2162.         
  2163.         deafult:
  2164.             error = errAECantSupplyType;
  2165.     }
  2166.     
  2167. CleanUp:
  2168.     
  2169.     return error;
  2170. }
  2171.  
  2172. #pragma mark -
  2173. // -------------------------------------------------------------------------------------------
  2174. //
  2175. //   SetDataForList
  2176. //
  2177. // Given a token that contains a list of cGraphicObject tokens,
  2178. // walk the list recursively to set the data for each token in the list
  2179. //
  2180. // -------------------------------------------------------------------------------------------
  2181.  
  2182. static OSErr
  2183. SetDataForList(AEDesc *token, AEDesc *data)
  2184. {
  2185.     OSErr             error          = noErr;    
  2186.     AEDesc              tempToken      = {typeNull, nil};
  2187.     
  2188.     long                numItems;
  2189.     long                index;
  2190.     AEKeyword        keyword;
  2191.     
  2192.  
  2193.     if (token->descriptorType != typeAEList)
  2194.     {
  2195.         error = SetDataForObject(token, data);
  2196.     }
  2197.     else
  2198.     {
  2199.         error = AECountItems((AEDescList*)token, &numItems);
  2200.         if (error != noErr)
  2201.             goto CleanUp;
  2202.         
  2203.         for (index = 1; index <= numItems; index++)
  2204.         {
  2205.            error = AEGetNthDesc((AEDescList*)token, index, typeWildCard, &keyword, &tempToken);
  2206.             if (error != noErr)
  2207.                 goto CleanUp;
  2208.             
  2209.             if (tempToken.descriptorType != typeAEList)
  2210.             {
  2211.                 error = SetDataForObject(&tempToken, data);  // Set data from single item
  2212.             }
  2213.             else
  2214.             {
  2215.                 error = SetDataForList(&tempToken, data);     // Recurse sublist
  2216.             }
  2217.             if (error != noErr)
  2218.                 goto CleanUp;
  2219.                     
  2220.             AEDisposeDesc(&tempToken);
  2221.         }
  2222.     }
  2223.  
  2224. CleanUp:
  2225.         
  2226.     AEDisposeDesc(&tempToken);
  2227.     
  2228.     return error;
  2229. }
  2230.  
  2231. //----------------------------------------------------------------------------------
  2232. //                                       SetDataForObject
  2233. //----------------------------------------------------------------------------------
  2234. // Assumption: HandleSetData() has already filtered out all attempts
  2235. // to write to a read-only property, so we only handle the writeable properties here.
  2236.  
  2237. static OSErr 
  2238. SetDataForObject(AEDesc *token, AEDesc *data)
  2239. {
  2240.  
  2241.     OSErr                    error            = noErr;
  2242.     
  2243.     DocumentReference document     = nil;
  2244.     ElementReference  element        = nil;
  2245.     ElementType            elementType;
  2246.     
  2247.     Boolean                usePropertyCode;
  2248.     DescType                propertyCode;
  2249.     
  2250.     AEDesc propertyRecord             = {typeNull, nil};
  2251.     
  2252.     error = GetDocumentReferenceFromToken(token, &document);
  2253.     if (error != noErr)
  2254.         goto CleanUp;
  2255.  
  2256.     error = GetElementReferenceFromToken(token, &element);
  2257.     if (error != noErr)
  2258.         goto CleanUp;
  2259.  
  2260.     elementType = GetElementType(element);
  2261.     
  2262.     usePropertyCode = ExtractUsePropertyCodeFromToken(token);
  2263.     
  2264.     if (usePropertyCode)
  2265.     {
  2266.         propertyCode = ExtractPropertyCodeFromToken(token);
  2267.         
  2268.         // Convert the single property to a record containing one property
  2269.  
  2270.         if (data->descriptorType == typeAERecord)
  2271.         {        
  2272.             error = SetProperties(document, element, data);
  2273.         }
  2274.         else    // Build a record with one property
  2275.         {
  2276.             error = AECreateList(NULL, 0L, true, &propertyRecord);
  2277.             if (error != noErr)
  2278.                 goto CleanUp;
  2279.             
  2280.             error = AEPutKeyDesc(&propertyRecord, propertyCode, data);
  2281.             if (error != noErr)
  2282.                 goto CleanUp;
  2283.         
  2284.             error = SetProperties(document, element, &propertyRecord);
  2285.         }
  2286.     }
  2287.  
  2288.     // Draw the element with its new data
  2289.     
  2290.     if (error == noErr)
  2291.     {
  2292.         IMDraw(document);
  2293.     }
  2294.  
  2295. CleanUp:
  2296.  
  2297.     AEDisposeDesc(&propertyRecord);
  2298.     
  2299.     if (error == noErr)
  2300.         MarkDocumentAsChanged(document);
  2301.  
  2302.     return error;
  2303. }
  2304.  
  2305. //----------------------------------------------------------------------------------
  2306. //                                           SetProperties
  2307. //----------------------------------------------------------------------------------
  2308. // Set an object's properties from the record we receive
  2309.  
  2310. static OSErr 
  2311. SetProperties(DocumentReference document, ElementReference element, AEDesc *propertyRecord)
  2312. {
  2313.     OSErr                 error             = noErr;
  2314.     OSErr                 ignoreError     = noErr;
  2315.         
  2316.     long                     numProperties     = 0L;
  2317.     
  2318.     ElementType            elementType      = GetElementType(element);
  2319.         
  2320.     AEDesc                 data                 = {typeNull, nil};
  2321.     
  2322.     // Used in setting boundingBox for groups
  2323.     
  2324.     Rect         boundingBox;
  2325.     Rect         newBoundingBox;
  2326.     short        corner;
  2327.     Point    mousePt        = {0,0};
  2328.  
  2329.     if (propertyRecord == NULL || propertyRecord->descriptorType != typeAERecord)
  2330.     {
  2331.         error = errAEWrongDataType;
  2332.         goto CleanUp;
  2333.     }
  2334.                 
  2335.     error = AECountItems(propertyRecord, &numProperties);
  2336.         
  2337.     if (error != noErr || numProperties <= 0)
  2338.         goto CleanUp;    
  2339.  
  2340.     // ----------------------------- Bounding box of the new element ------------------------------
  2341.     // pBounds
  2342.     
  2343.     ignoreError = AEGetKeyDesc(propertyRecord, pBounds, typeQDRectangle, &data);
  2344.     if (ignoreError != errAEDescNotFound)
  2345.     {
  2346.         error = DescToRect(&data, &newBoundingBox);
  2347.         
  2348.         if (error == noErr)
  2349.         {    
  2350.             switch (elementType)
  2351.             {
  2352.                  case kQDPolygon:
  2353.                     {
  2354.                         PolyHandle     polygon             = GetElementPolygon(element);
  2355.                         
  2356.                         boundingBox = GetElementBoundingBox(element);
  2357.  
  2358.                         if (polygon == nil)
  2359.                         {
  2360.                             SetElementBoundingBox(element, newBoundingBox);
  2361.                         }
  2362.                         else
  2363.                         {
  2364.                             MapPoly(polygon, &boundingBox, &newBoundingBox);
  2365.                             SetElementBoundingBox(element, newBoundingBox);
  2366.                             SetElementPolygon(element, polygon);
  2367.                         }
  2368.                     }
  2369.                     break;
  2370.                     
  2371.                 case kGroup:
  2372.                     {
  2373.                         boundingBox = GetElementBoundingBox(element);
  2374.                         corner         = 0;
  2375.                         
  2376.                         // First, resize the group, if necessary
  2377.                         
  2378.                         ResizeElementData(document, element, newBoundingBox);
  2379.                             
  2380.                         // Then, move the group, if necessary
  2381.                         
  2382.                         if ((newBoundingBox.left != boundingBox.left) || (newBoundingBox.top != boundingBox.top))
  2383.                             MoveElementData(document, element, newBoundingBox.top, newBoundingBox.left);
  2384.                     }
  2385.                     break;
  2386.                     
  2387.                 default:
  2388.                     SetElementBoundingBox(element, newBoundingBox);
  2389.                     break;
  2390.             }
  2391.         }
  2392.     }
  2393.     
  2394.     // pLocation
  2395.     
  2396.     ignoreError = AEGetKeyDesc(propertyRecord, pLocation, typeQDPoint, &data);
  2397.     if (ignoreError != errAEDescNotFound)
  2398.     {
  2399.         Point upperLeft;
  2400.         error = DescToPoint(&data, &upperLeft);
  2401.         
  2402.         if (error == noErr)
  2403.         {
  2404.             MoveElementData(document, element, upperLeft.v, upperLeft.h);
  2405.         }
  2406.     }
  2407.     
  2408.     // pWidth
  2409.     
  2410.     ignoreError = AEGetKeyDesc(propertyRecord, pWidth, typeShortInteger, &data);
  2411.     if (ignoreError != errAEDescNotFound)
  2412.     {
  2413.         short width;
  2414.         error = DescToShort(&data, &width);
  2415.         
  2416.         if (error == noErr)
  2417.         {
  2418.             boundingBox = GetElementBoundingBox(element);
  2419.             boundingBox.right = boundingBox.left + width;
  2420.             SetElementBoundingBox(element, boundingBox);
  2421.         }
  2422.         AEDisposeDesc(&data);
  2423.     }
  2424.     
  2425.     // pHeight
  2426.     
  2427.     ignoreError = AEGetKeyDesc(propertyRecord, pHeight, typeShortInteger, &data);
  2428.     if (ignoreError != errAEDescNotFound)
  2429.     {
  2430.         short height;
  2431.         error = DescToShort(&data, &height);
  2432.         
  2433.         if (error == noErr)
  2434.         {
  2435.             boundingBox = GetElementBoundingBox(element);
  2436.             boundingBox.bottom = boundingBox.top + height;
  2437.             SetElementBoundingBox(element, boundingBox);
  2438.         }
  2439.         AEDisposeDesc(&data);
  2440.     }
  2441.     
  2442.     
  2443.     // ----------------------------- Stroke ------------------------------
  2444.  
  2445.     // pStrokeSize
  2446.     
  2447.     ignoreError = AEGetKeyDesc(propertyRecord, pStrokeSize, typeFloat, &data);
  2448.     if (ignoreError != errAEDescNotFound)
  2449.     {
  2450.         short double penSize = 1.0;
  2451.         error = DescToShortDouble(&data, &penSize);
  2452.         
  2453.         if (error == noErr)
  2454.         {
  2455.             SetElementStrokePenWidth(element,  (float)penSize);
  2456.             SetElementStrokePenHeight(element, (float)penSize);
  2457.         }
  2458.         AEDisposeDesc(&data);
  2459.     }
  2460.  
  2461.     // pStrokeColor
  2462.     // colors can be supplied as RGB values, a color name, or a color enumeration
  2463.     // Coercion handlers are called automatically for a color name or a color enumeration
  2464.     
  2465.     ignoreError = AEGetKeyDesc(propertyRecord, pStrokeColor, typeRGBColor, &data);
  2466.     if (ignoreError != errAEDescNotFound)
  2467.     {
  2468.         RGBColor                rgb;
  2469.         error = DescToRGBColor(&data, &rgb);
  2470.         
  2471.         if (error == noErr)
  2472.         {
  2473.             SetElementStrokeColor(element, rgb);
  2474.         }
  2475.         
  2476.         AEDisposeDesc(&data);
  2477.     }
  2478.         
  2479.     // ----------------------------- Fill ------------------------------
  2480.  
  2481.     // pFillColor
  2482.     // colors can be supplied as RGB values, a color name, or a color enumeration
  2483.     // Coercion handlers are called automatically for a color name or a color enumeration
  2484.     
  2485.     ignoreError = AEGetKeyDesc(propertyRecord, pFillColor, typeRGBColor, &data);
  2486.     if (ignoreError != errAEDescNotFound)
  2487.     {
  2488.         RGBColor             rgb;
  2489.                 
  2490.         error = DescToRGBColor(&data, &rgb);
  2491.         
  2492.         if (error == noErr)
  2493.         {
  2494.             SetElementFillColor(element, rgb);
  2495.         }
  2496.         AEDisposeDesc(&data);
  2497.     }
  2498.     
  2499.     
  2500.     // ----------------------------- Rounded Rectangle ------------------------------
  2501.  
  2502.     if (elementType == kQDRoundRect)
  2503.     {
  2504.         // oval height
  2505.         
  2506.         ignoreError = AEGetKeyDesc(propertyRecord, pCornerCurveHeight, typeShortInteger, &data);
  2507.         if (ignoreError != errAEDescNotFound)
  2508.         {
  2509.             short height;
  2510.             error = DescToShort(&data, &height);
  2511.             
  2512.             if (error == noErr)
  2513.             {
  2514.                 Point ovalSize = GetElementRoundRectOvalSize(element);
  2515.                 ovalSize.v = height;
  2516.                 SetElementRoundRectOvalSize(element, ovalSize);
  2517.             }
  2518.             AEDisposeDesc(&data);
  2519.         }
  2520.  
  2521.         // oval width
  2522.         
  2523.         ignoreError = AEGetKeyDesc(propertyRecord, pCornerCurveWidth, typeShortInteger, &data);
  2524.         if (ignoreError != errAEDescNotFound)
  2525.         {
  2526.             short width;
  2527.             error = DescToShort(&data, &width);
  2528.             
  2529.             if (error == noErr)
  2530.             {
  2531.                 Point ovalSize = GetElementRoundRectOvalSize(element);
  2532.                 ovalSize.h = width;
  2533.                 SetElementRoundRectOvalSize(element, ovalSize);
  2534.             }
  2535.             AEDisposeDesc(&data);
  2536.         }
  2537.     }
  2538.     
  2539.     // ----------------------------- Line ------------------------------
  2540.  
  2541.     if (elementType == kQDLine)
  2542.     {
  2543.         Point point;
  2544.  
  2545.         //start point
  2546.  
  2547.         ignoreError = AEGetKeyDesc(propertyRecord, pStartPoint, typeQDPoint, &data);
  2548.         if (ignoreError != errAEDescNotFound)
  2549.         {
  2550.             error = DescToPoint(&data, &point);
  2551.             
  2552.             if (error == noErr)
  2553.                 SetElementLineBeginPoint(element, point);
  2554.  
  2555.             AEDisposeDesc(&data);
  2556.         }
  2557.  
  2558.         // end point
  2559.  
  2560.         ignoreError = AEGetKeyDesc(propertyRecord, pEndPoint, typeQDPoint, &data);
  2561.         if (ignoreError != errAEDescNotFound)
  2562.         {
  2563.             Point point;
  2564.             error = DescToPoint(&data, &point);
  2565.             
  2566.             if (error == noErr)
  2567.                 SetElementLineEndPoint(element, point);
  2568.  
  2569.             AEDisposeDesc(&data);
  2570.         }
  2571.         
  2572.         boundingBox = CalculateElementBounds(element);                
  2573.         SetElementBoundingBox(element, boundingBox);
  2574.  
  2575.     }
  2576.     
  2577.     // ----------------------------- Group ------------------------------
  2578.  
  2579.     if (elementType == kGroup)
  2580.     {
  2581.         // pGraphicObjects  -- ex: set properties to {members: {oval 1, oval 2, rectangle 3}}
  2582.         
  2583.         ignoreError = AEGetKeyDesc(propertyRecord, pGraphicObjects, typeAEList, &data);
  2584.         if (ignoreError != errAEDescNotFound)
  2585.         {
  2586.             error = MakeGroupFromAEList(document, element, &data);
  2587.             if (error != noErr)
  2588.             {
  2589.                 DestroyElement(element);
  2590.                 goto CleanUp;
  2591.             }    
  2592.             AEDisposeDesc(&data);
  2593.         }
  2594.     }
  2595.         
  2596.     // ----------------------------- Polygon ------------------------------
  2597.     
  2598.     if (elementType == kQDPolygon)
  2599.     {
  2600.         // point list
  2601.  
  2602.         ignoreError = AEGetKeyDesc(propertyRecord, pPointList, typeAEList, &data);
  2603.         if (ignoreError != errAEDescNotFound)
  2604.         {
  2605.             error = MakePolygonFromAEPointList(document, element, &data);
  2606.             AEDisposeDesc(&data);
  2607.         }
  2608.  
  2609.     }
  2610.     
  2611. CleanUp:
  2612.  
  2613.     AEDisposeDesc(&data);
  2614.  
  2615.     return error;
  2616. }
  2617.  
  2618. #pragma mark -
  2619. //----------------------------------------------------------------------------------
  2620. //                                       MakeNewObject
  2621. //----------------------------------------------------------------------------------
  2622. // Assumption: HandleCreateElement() has already filtered out all attempts
  2623. // to write to create the wrong type of object for the container
  2624.  
  2625. // NOTE: the token can be a null descriptor {typeNull, nil}, in which case there is
  2626. //       no ospec for the insertion location.
  2627.  
  2628. static OSErr 
  2629. MakeNewObject(const DescType objectToCreate, 
  2630.                      const DescType insertionPosition, 
  2631.                      const AEDesc *token, 
  2632.                      const AEDesc *ptrToWithData, 
  2633.                      const AEDesc *ptrToWithProperties,
  2634.                      AppleEvent   *reply)
  2635. {
  2636.     OSErr                 error         = noErr;
  2637.     OSErr                    ignoreError = noErr;
  2638.     
  2639.     DocumentReference document     = nil;
  2640.     ElementReference  element         = nil;
  2641.     ElementReference  oldElement     = nil;
  2642.     ElementType            elementType;
  2643.         
  2644.     error = GetDocumentReferenceFromToken(token, &document);
  2645.     if (error == errAENoSuchObject)
  2646.     {
  2647.         document = GetFrontDocument(GetDocumentList());
  2648.         error = (document == nil) ? errAENoSuchObject : noErr;
  2649.     }
  2650.         
  2651.     // we don't necessarily have an element because we could be creating the first element
  2652.     // or we could have asked to create a new element "at beginning of document 1", etc.
  2653.     
  2654.     if (error == noErr)
  2655.     {
  2656.         error = GetElementReferenceFromToken(token, &oldElement);
  2657.         
  2658.         if (error == errAENoSuchObject)
  2659.         {
  2660.             error = noErr;
  2661.             oldElement = GetFirstElement(GetDocumentElementList(document));
  2662.         }
  2663.     }
  2664.     
  2665.     if (error == noErr)
  2666.     {
  2667.         error = ConvertObjectClassToElementType(objectToCreate, &elementType);
  2668.         
  2669.         if (error == noErr)
  2670.         {
  2671.             element    = CreateElement(GetDocumentElementList(document), elementType);
  2672.             error            = ElementError();
  2673.             if (error == noErr && element != nil)
  2674.             {
  2675.                 PopulateElementWithDefaultData(element);
  2676.             }
  2677.         }
  2678.                     
  2679.         // By default, elements are created at the end of the list
  2680.         // If insertionPosition == kAEBeginning, then all is OK,
  2681.         // otherwise we should orphan the new element and relocate it accordingly.
  2682.         
  2683.         // NOTE: it seems like calls to ...InsertingBefore and ...InsertingAfter
  2684.         // are backwards, but they're not because the appleevent constants are from
  2685.         // the users point of view - "after" means "behind", "before" means "in front of"
  2686.         // The element list, however, is sorted from back (1st created) to front (most-recently created),
  2687.         // so that InsertingBefore an element actually places it behind that element visually.
  2688.         
  2689.         if (error == noErr)
  2690.         {
  2691.             switch (insertionPosition)
  2692.             {
  2693.                 case kAEBeginning:
  2694.                     // default behavior creates element as frontmost object
  2695.                     error = noErr;  // Just so the debugger can single step and stop here.
  2696.                     break;
  2697.                     
  2698.                 case kAEEnd:
  2699.                     if (oldElement != nil && element != oldElement)
  2700.                     {
  2701.                         OrphanElement(element);
  2702.                         AdoptOrphanInsertingBeforeElement(element, oldElement);
  2703.                     }
  2704.                     break;
  2705.                     
  2706.                 case kAEBefore:
  2707.                     if (oldElement != nil && element != oldElement)
  2708.                     {
  2709.                         OrphanElement(element);
  2710.                         AdoptOrphanInsertingAfterElement(element, oldElement);
  2711.                     }
  2712.                     break;
  2713.                     
  2714.                 case kAEAfter:
  2715.                     if (oldElement != nil && element != oldElement)
  2716.                     {
  2717.                         OrphanElement(element);
  2718.                         AdoptOrphanInsertingBeforeElement(element, oldElement);
  2719.                     }
  2720.                     break;
  2721.                     
  2722.                 case kAEReplace:
  2723.                     if (oldElement != nil && element != oldElement)
  2724.                     {
  2725.                         OrphanElement(element);
  2726.                         AdoptOrphanInsertingAfterElement(element, oldElement);
  2727.                         DestroyElement(oldElement);
  2728.                     }
  2729.                     break;
  2730.                     
  2731.                 default:
  2732.                     SysBeep(2);
  2733.                     break;    
  2734.             }            
  2735.         }
  2736.  
  2737.         // ==================================================================================
  2738.         // First, insert any data we received
  2739.         // ==================================================================================
  2740.         
  2741.         if (error == noErr && ptrToWithData != NULL)
  2742.         {
  2743.             DescType         dataType     = ptrToWithData->descriptorType;
  2744.             Handle           dataSource  = ptrToWithData->dataHandle;
  2745.     
  2746.             switch (dataType)
  2747.             {
  2748.                 case typeNull:
  2749.                     break;
  2750.                     
  2751.                 case typeChar:
  2752.                     switch (GetElementType(element))
  2753.                     {
  2754.                         default:
  2755.                             break;    // we don't support data for elements yet
  2756.                     }
  2757.                         break;
  2758.                             
  2759.                 default:
  2760.                     break;
  2761.             }
  2762.         }
  2763.         
  2764.         // ==================================================================================
  2765.         // Now, apply properties, if we received any.
  2766.         // ==================================================================================
  2767.         
  2768.         if (error == noErr && ptrToWithProperties != NULL)
  2769.         {
  2770.             error = SetProperties(document, element, (AEDesc *)ptrToWithProperties);
  2771.         }
  2772.         
  2773.         // if we created the new element, draw it
  2774.         
  2775.         if (error == noErr && element != nil)
  2776.         {
  2777.             IMDraw(document);
  2778.             MarkDocumentAsChanged(document);
  2779.         }
  2780.         
  2781.     }
  2782.  
  2783.     // return a reference to the new graphic object in the AppleEvent reply parameter
  2784.     
  2785.     if (error == noErr && reply != NULL && document != nil && element != nil)
  2786.     {
  2787.         AEDesc ospec = {typeNull, nil};
  2788.  
  2789.         error = CreateGraphicObjectOSpec(document, element, &ospec);
  2790.         
  2791.         if (error == noErr)
  2792.         {
  2793.             AEPutParamDesc(reply, keyDirectObject, &ospec);
  2794.         }
  2795.     
  2796.         AEDisposeDesc(&ospec);
  2797.     }
  2798.     
  2799. CleanUp:
  2800.  
  2801.     return error;
  2802. }
  2803.  
  2804. #pragma mark -
  2805. //----------------------------------------------------------------------------------
  2806. // Typically something like "move <rectangle 1> to <after> <oval 2>"
  2807.  
  2808. OSErr
  2809. DoMove(AEDesc *moveToken, DescType insertionPos, AEDesc *toToken)
  2810. {
  2811.  
  2812.     OSErr error                 = noErr;
  2813.     Boolean  movedIt        = false;
  2814.     
  2815.     DescType moveTokenType  = moveToken->descriptorType;
  2816.     DescType toTokenType     = toToken->descriptorType;
  2817.  
  2818.     DocumentReference document    = nil;
  2819.     ElementReference  moveElement = nil;
  2820.     ElementReference  toElement   = nil;
  2821.  
  2822.     GetDocumentReferenceFromToken(moveToken, &document);
  2823.     GetElementReferenceFromToken(moveToken, &moveElement);
  2824.     
  2825.     if (moveTokenType != typeNull)
  2826.         GetElementReferenceFromToken(toToken, &toElement);
  2827.     
  2828.     switch (insertionPos)
  2829.     {
  2830.         case kAEBeginning:
  2831.             // Get the last (frontmost) element, but make sure it's not the
  2832.             // element we are trying to move
  2833.             toElement = GetFirstElement(GetDocumentElementList(document));
  2834.             while (GetNextElement(toElement) != nil)
  2835.                 toElement = GetNextElement(toElement);
  2836.             if (toElement != nil && toElement != moveElement)
  2837.             {
  2838.                 OrphanElement(moveElement);
  2839.                 AdoptOrphanInsertingAfterElement(moveElement, toElement);
  2840.                 movedIt = true;
  2841.             }
  2842.             
  2843.             break;
  2844.             
  2845.         case kAEEnd:
  2846.             toElement = GetFirstElement(GetFirstElement(GetDocumentElementList(document)));
  2847.             if (toElement != nil && toElement != moveElement)
  2848.             {
  2849.                 OrphanElement(moveElement);
  2850.                 AdoptOrphanInsertingBeforeElement(moveElement, toElement);
  2851.                 movedIt = true;
  2852.             }
  2853.             break;
  2854.             
  2855.         case kAEBefore:
  2856.             if (toElement != nil && toElement != moveElement)
  2857.             {
  2858.                 OrphanElement(moveElement);
  2859.                 AdoptOrphanInsertingAfterElement(moveElement, toElement);
  2860.                 movedIt = true;
  2861.             }
  2862.             break;
  2863.             
  2864.         case kAEAfter:
  2865.             if (toElement != nil && toElement != moveElement)
  2866.             {
  2867.                 OrphanElement(moveElement);
  2868.                 AdoptOrphanInsertingBeforeElement(moveElement, toElement);
  2869.                 movedIt = true;
  2870.             }
  2871.             break;
  2872.             
  2873.         case kAEReplace:
  2874.             if (toElement != nil && toElement != moveElement)
  2875.             {
  2876.                 OrphanElement(moveElement);
  2877.                 AdoptOrphanInsertingAfterElement(moveElement, toElement);
  2878.                 DestroyElement(toElement);
  2879.                 toElement = nil;
  2880.                 movedIt = true;
  2881.             }
  2882.             break;
  2883.             
  2884.         default:
  2885.             SysBeep(2);
  2886.             break;    
  2887.     }            
  2888.     
  2889.     if (movedIt)
  2890.     {
  2891.         IMDraw(document);
  2892.         MarkDocumentAsChanged(document);        
  2893.     }
  2894.  
  2895.     return error;
  2896. }
  2897.  
  2898.  
  2899. #pragma mark -
  2900. //----------------------------------------------------------------------------------
  2901.  
  2902. #define kMaximumPolygonPoints    400
  2903.  
  2904. static OSErr
  2905. MakePolygonFromAEPointList(DocumentReference document, ElementReference element, AEDescList* list)
  2906. {
  2907.     #pragma unused (document)
  2908.  
  2909.     OSErr            error;
  2910.     
  2911.     Point       aPoint;
  2912.     Point       zeroPoint = {0,0};
  2913.     Point            pointList[kMaximumPolygonPoints];
  2914.     long             index;
  2915.     long             numPoints;
  2916.     AEKeyword    keyword;
  2917.     DescType    actualType;
  2918.     Size            actualSize;
  2919.     
  2920.     PolyHandle  polygon = nil;
  2921.     
  2922.     error = AECountItems(list, &numPoints);
  2923.     
  2924.     if (error == noErr && numPoints > kMaximumPolygonPoints)
  2925.         error = errAEEventNotHandled;
  2926.     
  2927.     if (error == noErr)
  2928.     {
  2929.         for (index = 1; index <= numPoints; index++)
  2930.         {
  2931.             error = AEGetNthPtr(list, index, typeQDPoint, 
  2932.                                         &keyword, &actualType, 
  2933.                                         &aPoint, sizeof(aPoint), 
  2934.                                         &actualSize);
  2935.            if (error == noErr)
  2936.                pointList[index-1] = aPoint;
  2937.            else
  2938.                pointList[index-1] = zeroPoint;
  2939.         }    
  2940.     }
  2941.     
  2942.     if (error == noErr)
  2943.     {
  2944.         polygon = CreatePolygonFromPoints(numPoints, pointList);
  2945.         
  2946.         if (polygon == nil)
  2947.         {
  2948.             error = errAEEventNotHandled;
  2949.         }
  2950.         else
  2951.         {
  2952.             SetElementPolygon(element, polygon);
  2953.             SetElementBoundingBox(element, (**polygon).polyBBox);
  2954.         }    
  2955.     }
  2956.     
  2957.     return error;
  2958. }
  2959.  
  2960. //----------------------------------------------------------------------------------
  2961. // On entry, the element is an empty group element and the object specifiers in
  2962. // the list are the objects that will be added to the new group
  2963.  
  2964. #define MAX_GROUP_MEMBERS 100
  2965.  
  2966. static OSErr
  2967. MakeGroupFromAEList(DocumentReference document, ElementReference group, AEDescList* list)
  2968. {
  2969.     OSErr                        error;
  2970.     
  2971.     long                         index;
  2972.     long                         numObjects;
  2973.     AEKeyword                keyword;
  2974.         
  2975.     AEDesc                    ospec                = {typeNull, nil};
  2976.     AEDesc                   token                = {typeNull, nil};
  2977.         
  2978.     ElementReference        member[MAX_GROUP_MEMBERS];
  2979.     long                        memberIndex    = 0;
  2980.     
  2981.     Assert(GetElementType(group) == kGroup, "Element passed in is not a group");
  2982.  
  2983.     error = AECountItems(list, &numObjects);
  2984.     if (error != noErr || numObjects < 2)
  2985.     {
  2986.         error = errAEEventNotHandled;
  2987.         goto CleanUp;
  2988.     }
  2989.         
  2990.     // This is divided into two steps. The first just builds a list of element references
  2991.     // for those elements that will be added to the list.
  2992.     // The second step removes those elements from the element list and adds them to the subelement list
  2993.     // of the group object.
  2994.     // This two-step approach is necessary so that we're not removing elements as we go, which
  2995.     // would then throw off AEResolve() when it was trying to find objects by thier index value.
  2996.     
  2997.     if (error == noErr)
  2998.     {
  2999.         ElementReference  memberElement;
  3000.         DocumentReference    memberDocument;
  3001.         Rect                    bounds;
  3002.         
  3003.         for (index = 1; index <= numObjects; index++)
  3004.         {
  3005.             error = AEGetNthDesc(list, index, typeObjectSpecifier, &keyword, &ospec);
  3006.            if (error == noErr)
  3007.            {
  3008.                error = AEResolve(&ospec, kAEIDoMinimum, &token);
  3009.            }
  3010.            
  3011.             if (error == noErr)
  3012.             {
  3013.                 error = GetDocumentReferenceFromToken(&token, &memberDocument);
  3014.                 if (error != noErr)
  3015.                 {
  3016.                     goto CleanUp;
  3017.                 }
  3018.                 else if (document != memberDocument)
  3019.                 {
  3020.                     error = errAEEventNotHandled;
  3021.                     goto CleanUp;
  3022.                 }
  3023.                 
  3024.                 error = GetElementReferenceFromToken(&token, &memberElement);
  3025.                 if (error != noErr)
  3026.                     goto CleanUp;
  3027.                 
  3028.                 member[memberIndex] = memberElement;
  3029.                 memberIndex++;
  3030.                 
  3031.                 AEDisposeDesc(&ospec);
  3032.                 AEDisposeDesc(&token);
  3033.             }
  3034.         }    
  3035.         
  3036.         for (index = 0; index < memberIndex; index++)
  3037.         {
  3038.             OrphanElement(member[index]);
  3039.             AdoptOrphan(GetElementSubElementList(group), member[index]);
  3040.         }
  3041.         
  3042.         bounds = CalculateElementBounds(group);
  3043.         SetElementBoundingBox(group, bounds);
  3044.     }
  3045.  
  3046. CleanUp:
  3047.                     
  3048.     AEDisposeDesc(&ospec);
  3049.     AEDisposeDesc(&token);
  3050.     
  3051.     return error;
  3052. }
  3053.  
  3054. #pragma mark -
  3055. // -------------------------------------------------------------------------------------------
  3056.  
  3057. static OSErr 
  3058. ProcessFormRelativePostition(const AEDesc* containerToken, const AEDesc *keyData, DescType desiredClass, ElementReference *element)
  3059. {
  3060.     OSErr                    error = noErr;
  3061.     
  3062.     OSType                 positionEnum;
  3063.     
  3064.     ElementReference     containerElement;
  3065.     ElementReference  relativeElement;
  3066.     
  3067.     ElementType            elementType;
  3068.     Boolean                foundIt                 = false;
  3069.     
  3070.     *element = nil;
  3071.     
  3072.     error = GetElementReferenceFromToken(containerToken, &containerElement);
  3073.     if (error != noErr)
  3074.         goto CleanUp;
  3075.     
  3076.     ConvertObjectClassToElementType(desiredClass, &elementType);
  3077.  
  3078.     switch (keyData->descriptorType)
  3079.     {
  3080.        case typeEnumerated:
  3081.             if (DescToDescType((AEDesc*)keyData, &positionEnum) != noErr)
  3082.             {
  3083.                 error = errAECoercionFail;
  3084.                 goto CleanUp;
  3085.             }
  3086.             
  3087.             switch (positionEnum)
  3088.             {
  3089.                 case kAENext:                        
  3090.                     // get the next object of the desired type (ie, the one behind the container)
  3091.                     relativeElement = GetPreviousElement(containerElement);
  3092.                     foundIt = (relativeElement != nil && GetElementType(relativeElement) == elementType) ? true : false;
  3093.                     while (relativeElement != nil && foundIt == false)
  3094.                     {
  3095.                         relativeElement = GetPreviousElement(relativeElement);
  3096.                         foundIt = (relativeElement != nil && GetElementType(relativeElement) == elementType) ? true : false;
  3097.                     }
  3098.                     
  3099.                     if (foundIt == false)
  3100.                         error = errAENoSuchObject;
  3101.                          
  3102.                     break;
  3103.                     
  3104.                 case kAEPrevious:        
  3105.                     // get the previous object of the desired type (ie, the one in front of the container)
  3106.                     relativeElement = GetNextElement(containerElement);
  3107.                     foundIt = (relativeElement != nil && GetElementType(relativeElement) == elementType) ? true : false;
  3108.                     while (relativeElement != nil && foundIt == false)
  3109.                     {
  3110.                         relativeElement = GetNextElement(relativeElement);
  3111.                         foundIt = (relativeElement != nil && GetElementType(relativeElement) == elementType) ? true : false;
  3112.                     }
  3113.                     
  3114.                     if (foundIt == false)
  3115.                         error = errAENoSuchObject;
  3116.                          
  3117.                     break;
  3118.                     
  3119.                 default:
  3120.                     error = errAEEventNotHandled;
  3121.                     goto CleanUp;
  3122.                     break;
  3123.             }
  3124.             break;
  3125.             
  3126.         default:
  3127.             error = errAECoercionFail;
  3128.             break;
  3129.     }
  3130.  
  3131. CleanUp:
  3132.     
  3133.     if (foundIt)
  3134.         *element = relativeElement;
  3135.         
  3136.     return error;
  3137. }
  3138.  
  3139. #pragma mark -
  3140. // -------------------------------------------------------------------------------------------
  3141.  
  3142. Boolean CanGetProperty(DescType class, DescType property)
  3143. {
  3144.     Boolean result;
  3145.     
  3146.     switch(property)
  3147.     {
  3148.         case pBestType:
  3149.         case pClass:
  3150.         case pDefaultType:
  3151.         case pObjectType:
  3152.         
  3153.         case pProperties:        
  3154.         case pID:
  3155.  
  3156.         case pBounds:
  3157.         case pLocation:
  3158.         case pWidth:
  3159.         case pHeight:
  3160.  
  3161.         case pStrokeSize:
  3162.         case pStrokeColor:
  3163.  
  3164.         case pFillColor:
  3165.             result = true;
  3166.             break;
  3167.         
  3168.         // depends on class of object:
  3169.         
  3170.         case pContents:
  3171.             result = (class == cGroupedGraphic);
  3172.             break;
  3173.         
  3174.         case pPointList:
  3175.             result = (class == cPolygon);
  3176.             break;
  3177.         
  3178.         case pCornerCurveHeight:
  3179.         case pCornerCurveWidth:
  3180.             result = (class == cRoundedRectangle);
  3181.             break;
  3182.         
  3183.         case pStartPoint:
  3184.         case pEndPoint:
  3185.             result = (class == cGraphicLine);
  3186.             break;
  3187.                 
  3188.         case pGraphicObjects:
  3189.             result = (class == cGroupedGraphic);
  3190.             break;
  3191.  
  3192.         default:
  3193.             result = false;
  3194.             break;
  3195.     }
  3196.  
  3197.     return result;
  3198. }
  3199.  
  3200. // -------------------------------------------------------------------------------------------
  3201.  
  3202. Boolean CanSetProperty(DescType class, DescType property)
  3203. {
  3204.     Boolean result;
  3205.     
  3206.     switch(property)
  3207.     {
  3208.         // can always be set:
  3209.         
  3210.         case pBounds:
  3211.         case pLocation:
  3212.         case pWidth:
  3213.         case pHeight:
  3214.  
  3215.         case pProperties:
  3216.                 
  3217.         case pStrokeSize:
  3218.         case pStrokeColor:
  3219.  
  3220.         case pFillColor:
  3221.             result = true;
  3222.             break;
  3223.             
  3224.         // depends on class of object:
  3225.         
  3226.         case pPointList:
  3227.             result = (class == cPolygon);
  3228.             break;
  3229.                 
  3230.         case pCornerCurveHeight:
  3231.         case pCornerCurveWidth:
  3232.             result = (class == cRoundedRectangle);
  3233.             break;
  3234.             
  3235.         case pEndPoint:
  3236.         case pStartPoint:
  3237.             result = (class == cGraphicLine);
  3238.             break;
  3239.         
  3240.         case pGraphicObjects:
  3241.             result = (class == cGroupedGraphic);
  3242.             break;
  3243.         
  3244.         // should be able to set, but not implemented yet:
  3245.         
  3246.         case pContents:
  3247.             result = false;
  3248.             break;
  3249.             
  3250.         // can never be set:
  3251.         
  3252.         default:
  3253.             result = false;
  3254.             break;
  3255.     }
  3256.  
  3257.     return result;
  3258. }
  3259.  
  3260. /*****************************************************************************
  3261.  * 
  3262.  * CreatePolygonFromPoints
  3263.  * 
  3264.  * Create a polygon element from a list of points
  3265.  * 
  3266.  *****************************************************************************/
  3267. PolyHandle CreatePolygonFromPoints(short numberOfPoints, Point *pointList)
  3268. {
  3269.     Boolean    polyClosed = false;
  3270.     PolyHandle polyHandle = OpenPoly();
  3271.     short          pointIndex;
  3272.     
  3273.     if (polyHandle == nil)
  3274.         return polyHandle;
  3275.         
  3276.     // Move to the first point
  3277.     
  3278.     MoveTo(pointList[0].h, pointList[0].v);
  3279.     
  3280.     // Line to the rest of the points
  3281.     
  3282.     pointIndex = 1;
  3283.     while (pointIndex < numberOfPoints)
  3284.     {
  3285.         LineTo(pointList[pointIndex].h, pointList[pointIndex].v);
  3286.        pointIndex++;
  3287.     }
  3288.     
  3289.     // Make sure the polygon is a closed object
  3290.     
  3291.     if ((pointList[0].h != pointList[numberOfPoints-1].h) || (pointList[0].v != pointList[numberOfPoints-1].v))
  3292.         LineTo(pointList[0].h, pointList[0].v);
  3293.     
  3294.     ClosePoly();
  3295.     
  3296.     return polyHandle;
  3297. }
  3298.  
  3299. /*****************************************************************************
  3300.  * 
  3301.  * CountPolygonPoints
  3302.  * 
  3303.  * Returns the number of points owned by a polygon
  3304.  * 
  3305.  *****************************************************************************/
  3306. static short CountPolygonPoints(PolyHandle polygon)
  3307. {
  3308.     return(((**polygon).polySize - sizeof(short) - sizeof(Rect)) / sizeof(Point));
  3309. }
  3310.  
  3311.  
  3312. /*****************************************************************************
  3313.  * 
  3314.  * GetPolygonPoint
  3315.  * 
  3316.  * Returns the specified point. Note that the index is one based, to get the
  3317.  * first point, pass 1.
  3318.  * 
  3319.  *****************************************************************************/
  3320.  
  3321. static Point GetPolygonPoint(PolyHandle polygon, short pointIndex)
  3322. {
  3323.     Point        pt;
  3324.     short        numPts;
  3325.     
  3326.     pt.v = 0;                                                                                    // assume failure
  3327.     pt.h = 0;
  3328.     
  3329.     numPts = CountPolygonPoints(polygon);                                                // found out how many are in the polygon
  3330.     if ((pointIndex >= 1) && (pointIndex <= numPts))                                // sanity check
  3331.         pt = (**polygon).polyPoints[pointIndex - 1];                                    // extract the point
  3332.     
  3333.     return(pt);                                                                                    // return it to the caller
  3334. }
  3335.  
  3336.  
  3337.